[IOI2018] werewolf 狼人
IOI2018题解
(其实原题强制在线,要用主席树)
代码:
注意:
1.下标从0~n-1
2.kruskal重构树开始有n个节点,tot从n开始,++tot
#include<bits/stdc++.h> #define reg register int #define il inline #define numb (ch^'0') using namespace std; typedef long long ll; il void rd(int &x){char ch;x=0;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x); } namespace Miracle{ const int M=400000+5; const int N=400000+5; const int inf=0x3f3f3f3f; int n,m,Q; struct edge{int x,y;int val; }b[M]; bool cmp0(edge a,edge b){return a.val<b.val; } bool cmp1(edge a,edge b){return a.val>b.val; } int fafa[2*N];struct kruskal{struct node{int nxt,to;}e[2*N];int hd[2*N],cnt;int fin(int x){return fafa[x]==x?x:fafa[x]=fin(fafa[x]);}void add(int x,int y){e[++cnt].nxt=hd[x];e[cnt].to=y;hd[x]=cnt;}int tot;void build(int typ){for(reg i=1;i<=n;++i){if(typ) val[i]=inf;else val[i]=-inf;}tot=n;for(reg i=1;i<=m;++i){int k1=fin(b[i].x),k2=fin(b[i].y);// cout<<" edge "<<b[i].x<<" "<<b[i].y<<" :: "<<k1<<" "<<k2<<endl;if(k1!=k2){++tot;fafa[tot]=tot;fafa[k1]=tot;fafa[k2]=tot;val[tot]=b[i].val;add(tot,k1);add(tot,k2);}}}int l[N],r[N];int val[N];int fa[N][20];int df;void dfs(int x){// cout<<" xx "<<x<<endl;int son=0;r[x]=-inf;l[x]=inf;for(reg i=hd[x];i;i=e[i].nxt){int y=e[i].to;++son;dfs(y);fa[y][0]=x;r[x]=max(r[x],r[y]);l[x]=min(l[x],l[y]);}if(!son){l[x]=r[x]=++df;}}void pre(){dfs(tot);for(reg j=1;j<=19;++j){for(reg i=1;i<=tot;++i){fa[i][j]=fa[fa[i][j-1]][j-1];}}}int fin(int x,int lim,int typ){//beizeng go valint p=x;if(!typ){//go <=limfor(reg j=19;j>=0;--j){if(fa[p][j]){if(val[fa[p][j]]<=lim) p=fa[p][j];}}return p;}else{//go >=limfor(reg j=19;j>=0;--j){if(fa[p][j]){if(val[fa[p][j]]>=lim) p=fa[p][j];}}return p;}} }kt[2];//0:min tree;1:max tree;int num; struct po{int x,y;bool friend operator <(po a,po b){return a.x<b.x;} }p[N]; int ans[N];int tot; struct que{int id,x,typ,y1,y2;bool friend operator <(que a,que b){return a.x<b.x;} }q[N*2];struct binarytree{int f[N];void upda(int x){for(;x<=n;x+=x&(-x)) f[x]++;}int query(int x){int ret=0;for(;x;x-=x&(-x)) ret+=f[x];return ret;} }t; int main(){rd(n);rd(m);rd(Q);for(reg i=1;i<=m;++i){rd(b[i].x);rd(b[i].y);++b[i].x;++b[i].y;//warning!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! b[i].val=max(b[i].x,b[i].y);}sort(b+1,b+m+1,cmp0);for(reg i=1;i<=2*n;++i){fafa[i]=i;}kt[0].build(0);kt[0].pre(); // cout<<" after build small "<<endl;for(reg i=1;i<=m;++i){b[i].val=min(b[i].x,b[i].y);}sort(b+1,b+m+1,cmp1);for(reg i=1;i<=2*n;++i){fafa[i]=i;}kt[1].build(1);kt[1].pre();int st,nd,L,R;for(reg i=1;i<=Q;++i){rd(st);rd(nd);rd(L);rd(R);++L;++R;++st;++nd;//warning!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!int ptr=kt[1].fin(st,L,1);q[++tot].id=i;q[tot].y1=kt[1].l[ptr];q[tot].y2=kt[1].r[ptr];q[++tot].id=i;q[tot].y1=kt[1].l[ptr];q[tot].y2=kt[1].r[ptr];ptr=kt[0].fin(nd,R,0);q[tot-1].x=kt[0].l[ptr]-1;q[tot].x=kt[0].r[ptr];q[tot-1].typ=-1;q[tot].typ=1;}sort(q+1,q+tot+1);for(reg i=1;i<=n;++i){p[i].x=kt[0].l[i];p[i].y=kt[1].l[i];}sort(p+1,p+n+1);int ptp=1,ptq=1;for(reg i=1;i<=n;++i){while(ptp<=n&&p[ptp].x<i) ++ptp;if(p[ptp].x==i){while(ptp<=n&&p[ptp].x==i){t.upda(p[ptp].y);++ptp;}}while(ptq<=tot&&q[ptq].x<i) ++ptq;if(q[ptq].x==i){while(ptq<=tot&&q[ptq].x==i){ans[q[ptq].id]+=q[ptq].typ*(t.query(q[ptq].y2)-t.query(q[ptq].y1-1));++ptq;}}}for(reg i=1;i<=Q;++i){puts(ans[i]?"1":"0");}return 0; }} signed main(){Miracle::main();return 0; }/*Author: *Miracle*Date: 2019/2/10 15:50:00 */
总结:
kruskal重构树,就是考虑在经过边权在一定范围内到达的区域的点的情况
这里就是简单查询连通性
两个重构树判交的“二维数点”问题的转化很巧妙!