记录编号 |
133856 |
评测结果 |
AAAAAAAAAAAAAAAAAAAA |
题目名称 |
[国家集训队2012]Attack |
最终得分 |
100 |
用户昵称 |
cstdio |
是否通过 |
通过 |
代码语言 |
C++ |
运行时间 |
24.439 s |
提交时间 |
2014-10-28 20:52:03 |
内存使用 |
112.66 MiB |
显示代码纯文本
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
const int SIZEB=310,SIZEN=60010,BLOCK_NODE=SIZEB*30;
class NODE{//函数式线段树的节点
public:
int sum;
int l,r;
int lson,rson;
void print(void){cout<<l<<" "<<r<<" "<<sum<<" "<<lson<<" "<<rson<<endl;}
void clear(int a,int b){
l=a,r=b;
sum=0;
lson=rson=-1;
}
};
NODE tree[SIZEN*100];
int tot=0;
void printtree(int x){//调试接口......
cout<<x<<": ";tree[x].print();
if(tree[x].lson!=-1) printtree(tree[x].lson);
if(tree[x].rson!=-1) printtree(tree[x].rson);
}
int build(int l,int r){
int x=tot++;
tree[x].clear(l,r);
if(l<r){
int mid=(l+r)/2;
tree[x].lson=build(l,mid);
tree[x].rson=build(mid+1,r);
}
return x;
}
int change(int x,int a,int t){
if(x==-1) return -1;
if(tree[x].l>a||tree[x].r<a) return x;
int p=tot++;
tree[p]=tree[x];
NODE &now=tree[p];
now.sum+=t;
now.lson=change(now.lson,a,t);
now.rson=change(now.rson,a,t);
return p;
}
int leftsum(int x){//左儿子的sum
return tree[tree[x].lson].sum;
}
class CITY{//城池
public:
int id;
int x,y,z;
void print(void){cout<<x<<" "<<y<<" "<<z<<endl;}
};
bool cmpx(CITY a,CITY b){
return a.x<b.x;
}
bool cmpy(CITY a,CITY b){
return a.y<b.y;
}
bool cmpz(CITY a,CITY b){
return a.z<b.z;
}
int WN;//权值的个数,从1到wn编号
int N,Q;
int T,BN;//每一块大小,块数
int belong[SIZEN],bpos[SIZEN];
int realz[SIZEN];
CITY cities[SIZEN];
class BLOCK{//分块后的一块
public:
int len;
int stx,edx;//开始和结束的x
CITY c[SIZEB];
int Y[SIZEB];
int root[SIZEB];
int head;//从这里开始
BLOCK(){len=0;}
void add(CITY t){
if(!len) stx=t.x;
c[++len]=t;
edx=t.x;
}
int stat(int x0,int y0,int x1,int y1,int l,int r){//在矩形内且z属于[k,r]的数量
int ans=0;
for(int i=1;i<=len;i++){
if(c[i].x<x0||c[i].x>x1||c[i].y<y0||c[i].y>y1) continue;
if(c[i].z<l||c[i].z>r) continue;
ans++;
}
return ans;
}
pair<int,int> get_window(int y0,int y1){//看y符合的是哪一段
pair<int,int> ans;
ans.first=lower_bound(Y+1,Y+1+len,y0)-Y;
ans.second=upper_bound(Y+1,Y+1+len,y1)-Y-1;
return ans;
}
void maketree(void){
tot=head;//放在分给它的内存中
root[0]=0;//在每个block里它都是零......不要在意
for(int i=1;i<=len;i++) root[i]=change(root[i-1],c[i].z,1);
}
void init(void){//按y排序,并建树
sort(c+1,c+1+len,cmpy);
maketree();
for(int i=1;i<=len;i++){
bpos[c[i].id]=i;
Y[i]=c[i].y;
}
}
}blocks[SIZEB];
vector<int> part;//两端的块
int full_l,full_r;//完整的
int nd0[SIZEB],nd1[SIZEB];//负,正节点的坐标
void mark_blocks(int a,int b){//得出中间/两端的块都有哪些,查询的x范围a~b
part.clear();
full_l=full_r=0;
for(int i=1;i<=BN;i++){
if(blocks[i].stx>b||blocks[i].edx<a) continue;
if(blocks[i].stx>=a&&blocks[i].edx<=b){
if(!full_l) full_l=i;
full_r=i;
}
else part.push_back(i);
}
}
void get_node(int y0,int y1){//得到"正节点"和"负节点"(区间和,也就是两棵线段树做减法)
pair<int,int> tp;
for(int i=full_l;i<=full_r;i++){
tp=blocks[i].get_window(y0,y1);
nd0[i]=blocks[i].root[tp.first-1];
nd1[i]=blocks[i].root[tp.second];
}
}
int calc_num(int x0,int y0,int x1,int y1,int l,int r){//计算矩形框内,z在[l,r]的数量
int ans=0;
for(int i=0;i<part.size();i++) ans+=blocks[part[i]].stat(x0,y0,x1,y1,l,r);
for(int i=full_l;i<=full_r;i++){
ans-=tree[nd0[i]].sum;
ans+=tree[nd1[i]].sum;
}
return ans;
}
int calc_left(int x0,int y0,int x1,int y1,int l,int r){//计算矩形框内,z在[l,r]的左边一半的数量
int ans=0,mid=(l+r)/2;
for(int i=0;i<part.size();i++) ans+=blocks[part[i]].stat(x0,y0,x1,y1,l,mid);
for(int i=full_l;i<=full_r;i++){
ans-=leftsum(nd0[i]);
ans+=leftsum(nd1[i]);
}
return ans;
}
void go_down(bool flag){//每个节点都向左/右儿子走,0左1右
for(int i=full_l;i<=full_r;i++){
if(!flag){
nd0[i]=tree[nd0[i]].lson;
nd1[i]=tree[nd1[i]].lson;
}
else{
nd0[i]=tree[nd0[i]].rson;
nd1[i]=tree[nd1[i]].rson;
}
}
}
void answer(int x0,int y0,int x1,int y1,int k){
mark_blocks(x0,x1);
get_node(y0,y1);
int l=1,r=WN;
if(calc_num(x0,y0,x1,y1,l,r)<k){
printf("It doesn't exist.\n");
return;
}
while(l<r){//二分离散化后的值
int t=calc_left(x0,y0,x1,y1,l,r);
int mid=(l+r)/2;
if(t<k){
k-=t;
l=mid+1;
go_down(1);
}
else{
r=mid;
go_down(0);
}
}
printf("%d\n",realz[l]);
}
void change(int a,int b){//交换二者
if(a==b) return;
swap(blocks[belong[a]].c[bpos[a]].z,blocks[belong[b]].c[bpos[b]].z);
blocks[belong[a]].maketree();
if(belong[b]!=belong[a]) blocks[belong[b]].maketree();
}
void work(void){
char cmd[20];
int x0,y0,x1,y1,k;
int x,y;
for(int i=1;i<=Q;i++){
scanf("%s",cmd);
if(cmd[0]=='Q'){
scanf("%d%d%d%d%d",&x0,&y0,&x1,&y1,&k);
if(x0>x1) swap(x0,x1);//反人类的输入格式......
if(y0>y1) swap(y0,y1);
answer(x0,y0,x1,y1,k);
}
else{
scanf("%d%d",&x,&y);
x++,y++;
change(x,y);
}
}
}
void allot_head(void){//给每一个块设置它在线段树中的内存起点
for(int i=1;i<=BN;i++){
blocks[i].head=tot;
tot+=BLOCK_NODE;
}
}
void make_blocks(void){//分好块
WN=0;
sort(cities+1,cities+1+N,cmpz);
int last;
for(int i=1;i<=N;i++){//将z离散化
if(i==1||cities[i].z!=last){
WN++;
realz[WN]=cities[i].z;
}
last=cities[i].z;
cities[i].z=WN;
}
sort(cities+1,cities+1+N,cmpx);
T=sqrt(N+0.5);
BN=1;int tot=0;
for(int i=1;i<=N;i++){//按x分块
tot++;
belong[cities[i].id]=BN;
blocks[BN].add(cities[i]);
if(i==N||tot==T){
BN++;
tot=0;
}
}
BN--;
build(1,WN);
allot_head();
for(int i=1;i<=BN;i++) blocks[i].init();//该块初始化
}
void read(void){
scanf("%d%d",&N,&Q);
for(int i=1;i<=N;i++){
cities[i].id=i;
scanf("%d%d%d",&cities[i].x,&cities[i].y,&cities[i].z);
}
}
int main(){
freopen("nt2012_attack.in","r",stdin);
freopen("nt2012_attack.out","w",stdout);
read();
make_blocks();
work();
return 0;
}