刷题总结——天使玩偶(bzoj2716)
题目:
Description
Input
Output
HINT
题解:
学了cdq后近期最后一道题···然而tm还是搞了1个半小时才tm搞出来······
先说思路:对于绝对值,我们采取类似于旋转整个图的方法,也就是说共计三次翻转再加上原来的图,每次旋转90度,算出点在旋转后的对应坐标(具体看代码中的注释部分),然后对于一个询问,每次只算它左上角的点的贡献,这样就有一个三维偏序:<时间,x,y>,时间已经在开始就默认排好了,由于此时dis=x-x1+y-y1=x+y-x1-y1,所以对于一个<时间,x,y>,我们要计算的是所有x1<x,y1<y,时间1<时间的点中x1+y1最大的点,这样dis就能最小;分析完基本思路后,接下来就是cdq的基本套路了,x1+y1用树状数组维护
但这道题让我发现了自己的许多细节错误,详细见代码注释
代码:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<ctime> #include<cctype> #include<cstring> #include<string> #include<algorithm> using namespace std; const int N=2e6+5; const int M=5e5+5; struct node { int x,y,id,pos; }a[N],q[N],tmp[N]; int n,m,tot,maxx,maxy,ans[M],cnt=0,tree[N],tag[N],tim; inline int R() { char c;int f=0; for(c=getchar();c<'0'||c>'9';c=getchar()); for(;c<='9'&&c>='0';c=getchar()) f=(f<<3)+(f<<1)+c-'0'; return f; } bool comp(node a,node b) { if(a.x==b.x) return a.id<b.id; //!!!!!注意一定要有这一点,x相同时一定要按时间排序!! else return a.x<b.x; } inline void insert(int u,int v) { for(int i=u;i<=maxy;i+=(i&(-i))) if(tag[i]!=tim) tag[i]=tim,tree[i]=v; else tree[i]=max(tree[i],v); } inline int query(int u) { int temp=0; for(int i=u;i;i-=(i&(-i))) if(tag[i]!=tim) continue; else temp=max(temp,tree[i]); return temp==0?-1e+8:temp; //注意这里!!! } inline void solve(int l,int r) { if(l==r) return; int mid=(l+r)/2; solve(l,mid),solve(mid+1,r); int i=l,j=mid+1,k=l;tim++; while(i<=mid&&j<=r) { if(comp(q[i],q[j])) { if(!q[i].pos) insert(q[i].y,q[i].x+q[i].y); tmp[k++]=q[i++]; } else { if(q[j].pos) ans[q[j].pos]=min(ans[q[j].pos],q[j].x+q[j].y-query(q[j].y)); tmp[k++]=q[j++]; } } while(i<=mid) tmp[k++]=q[i++]; while(j<=r) { if(q[j].pos) ans[q[j].pos]=min(ans[q[j].pos],q[j].x+q[j].y-query(q[j].y)); tmp[k++]=q[j++]; } for(j=l;j<=r;j++) q[j]=tmp[j]; } int main() { //freopen("a.in","r",stdin); n=R();m=R();int x,y,t; for(int i=1;i<=n;i++) { x=R()+1,y=R()+1; a[++tot].id=i,a[tot].x=x,a[tot].y=y; maxx=max(maxx,x),maxy=max(maxy,y); } for(int i=1;i<=m;i++) { t=R(),x=R()+1,y=R()+1; if(t==1) a[++tot].id=tot,a[tot].x=x,a[tot].y=y; else a[++tot].id=tot,a[tot].x=x,a[tot].y=y,a[tot].pos=++cnt; maxx=max(maxx,x),maxy=max(maxy,y); } maxx++,maxy++; for(int i=1;i<=cnt;i++) ans[i]=1e+8; for(int i=1;i<=tot;i++) q[i]=a[i]; //第一次,不用翻转 solve(1,tot); for(int i=1;i<=tot;i++) q[i]=a[i],q[i].x=maxx-a[i].x; //第一次翻转 (不一定是90度,把所有情况讨论了就行) solve(1,tot); for(int i=1;i<=tot;i++) q[i]=a[i],q[i].y=maxy-a[i].y; //第二次翻转 solve(1,tot); for(int i=1;i<=tot;i++) q[i]=a[i],q[i].x=maxx-a[i].x,q[i].y=maxy-a[i].y; //第三次翻转 solve(1,tot); for(int i=1;i<=cnt;i++) printf("%d\n",ans[i]); return 0; }