BZOJ4066: 简单题
Description
你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作:
命令 |
参数限制 |
内容 |
1 x y A |
1<=x,y<=N,A是正整数 |
将格子x,y里的数字加上A |
2 x1 y1 x2 y2 |
1<=x1<= x2<=N 1<=y1<= y2<=N |
输出x1 y1 x2 y2这个矩形内的数字和 |
3 |
无 |
终止程序 |
Input
输入文件第一行一个正整数N。
接下来每行一个操作。每条命令除第一个数字之外,
均要异或上一次输出的答案last_ans,初始时last_ans=0。
Output
对于每个2操作,输出一个对应的答案。
Sample Input
4
1 2 3 3
2 1 1 3 3
1 1 1 1
2 1 1 0 7
3
1 2 3 3
2 1 1 3 3
1 1 1 1
2 1 1 0 7
3
Sample Output
3
5
5
HINT
数据规模和约定
1<=N<=500000,操作数不超过200000个,内存限制20M,保证答案在int范围内并且解码之后数据仍合法。
样例解释见OJ2683
新加数据一组,但未重测----2015.05.24
隔壁AKC一眼CDQ发现是在线又一眼树套树发现MLE了。。
实在不是很会搞,分割平面那就KD-tree走一波
至于加值,那就是插点,查找就类似于线段树维护下子树和不行递归找
然后T掉了:多次加点使树的结构失衡,退化为平方级算法
那就暴力重构,每到一定范围就像替罪羊树一样强行拆开重构
//MT_LI #include<cmath> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; struct KDT{ int lc,rc,s,sum; int mn[2],mx[2],d[2]; }tr[500010]; void update(int x) { int lc=tr[x].lc,rc=tr[x].rc; if(lc) { tr[x].mn[0]=min(tr[x].mn[0],tr[lc].mn[0]); tr[x].mn[1]=min(tr[x].mn[1],tr[lc].mn[1]); tr[x].mx[0]=max(tr[x].mx[0],tr[lc].mx[0]); tr[x].mx[1]=max(tr[x].mx[1],tr[lc].mx[1]); tr[x].sum+=tr[lc].sum; } if(rc) { tr[x].mn[0]=min(tr[x].mn[0],tr[rc].mn[0]); tr[x].mn[1]=min(tr[x].mn[1],tr[rc].mn[1]); tr[x].mx[0]=max(tr[x].mx[0],tr[rc].mx[0]); tr[x].mx[1]=max(tr[x].mx[1],tr[rc].mx[1]); tr[x].sum+=tr[rc].sum; } } int cmpd,root; bool cmp(KDT a,KDT b){return a.d[cmpd]<b.d[cmpd] || a.d[cmpd]==b.d[cmpd]&&a.d[cmpd^1]<b.d[cmpd^1];} void ins(int now) { int p=root; while(1) { if(tr[p].mx[0]<tr[now].mx[0])tr[p].mx[0]=tr[now].mx[0]; if(tr[p].mx[1]<tr[now].mx[1])tr[p].mx[1]=tr[now].mx[1]; if(tr[p].mn[0]>tr[now].mn[0])tr[p].mn[0]=tr[now].mn[0]; if(tr[p].mn[1]>tr[now].mn[1])tr[p].mn[1]=tr[now].mn[1]; tr[p].sum+=tr[now].sum; if(tr[now].d[cmpd]<tr[p].d[cmpd]) { if(tr[p].lc==0){tr[p].lc=now;return ;} else p=tr[p].lc; } else { if(tr[p].rc==0){tr[p].rc=now;return ;} else p=tr[p].rc; } cmpd^=1; } } int find(int x,int x1,int y1,int x2,int y2) { if(tr[x].mn[0]>x2||tr[x].mn[1]>y2||tr[x].mx[0]<x1||tr[x].mx[1]<y1)return 0; if(tr[x].mx[0]<=x2&&tr[x].mx[1]<=y2&&tr[x].mn[0]>=x1&&tr[x].mn[1]>=y1)return tr[x].sum; int tot=0; if(tr[x].d[0]>=x1&&tr[x].d[1]>=y1&&tr[x].d[0]<=x2&&tr[x].d[1]<=y2)tot=tr[x].s; if(tr[x].lc)tot+=find(tr[x].lc,x1,y1,x2,y2); if(tr[x].rc)tot+=find(tr[x].rc,x1,y1,x2,y2); return tot; } int rebuild(int l,int r,int d) { int mid=(l+r)/2,now; now=mid;cmpd=d; nth_element(tr+l,tr+mid,tr+r+1,cmp); tr[now].mx[0]=tr[now].mn[0]=tr[now].d[0]; tr[now].mx[1]=tr[now].mn[1]=tr[now].d[1]; tr[now].sum=tr[now].s; if(l<mid)tr[now].lc=rebuild(l,mid-1,d^1); if(mid<r)tr[now].rc=rebuild(mid+1,r,d^1); update(now); return now; } int ans=0; int main() { int n;int cnt=0; scanf("%d",&n);root=0; while(1) { int op; scanf("%d",&op); if(op==3)break; if(op==1) { ++cnt; scanf("%d%d%d",&tr[cnt].d[0],&tr[cnt].d[1],&tr[cnt].s); tr[cnt].d[0]^=ans;tr[cnt].d[1]^=ans;tr[cnt].s^=ans; tr[cnt].mx[0]=tr[cnt].mn[0]=tr[cnt].d[0]; tr[cnt].mx[1]=tr[cnt].mn[1]=tr[cnt].d[1]; tr[cnt].sum=tr[cnt].s; if(cnt%10000==0) { for(int i=1;i<=cnt;i++)tr[i].lc=tr[i].rc=0; root=rebuild(1,cnt,0); continue; } if(root==0)root=cnt; else cmpd=0,ins(cnt); } else { int x1,x2,y1,y2; scanf("%d%d%d%d",&x1,&y1,&x2,&y2); x1^=ans;x2^=ans;y1^=ans;y2^=ans; ans=find(root,x1,y1,x2,y2); printf("%d\n",ans); } } return 0; }
The deepest love I think,later than apart,I will live as you like