bzoj4025: 二分图
这题想不出来。
不浪费时间了。
以后找时间填。
--------------------update---------------
就是判奇环咯
然而LCT我搞不出来。。
是因为对于当前的最大生成树,新时间加入的边可能是比前面最大生成树里最小边要大,然后就要找到最大生成树里最小的边。。这样要化边为点我萎了还是写不出来你们去%吧
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<queue> #include<map> using namespace std; struct node { int x,y; }a[210000]; struct heap_st { int st,ed,id; friend bool operator>(heap_st n1,heap_st n2){return n1.st>n2.st;} };priority_queue<heap_st,vector<heap_st>,greater<heap_st> >A; struct heap_ed { int ed,id; friend bool operator>(heap_ed n1,heap_ed n2){return n1.ed>n2.ed;} };priority_queue<heap_ed,vector<heap_ed>,greater<heap_ed> >B; struct heap_mt { int ed,id; friend bool operator>(heap_mt n1,heap_mt n2){return n1.ed<n2.ed;} };priority_queue<heap_mt,vector<heap_mt>,greater<heap_mt> >C; //---------edge&&heap--------------- struct LCT { int f,c,son[2]; bool fz; }tr[210000]; void yu(int n){for(int i=1;i<=n;i++)tr[i].c=1,tr[i].fz=false;} void update(int x) { int lc=tr[x].son[0],rc=tr[x].son[1]; tr[x].c=tr[lc].c+tr[rc].c+1; } void reverse(int x) { tr[x].fz=false; swap(tr[x].son[0],tr[x].son[1]); int lc=tr[x].son[0],rc=tr[x].son[1]; tr[lc].fz=1-tr[lc].fz; tr[rc].fz=1-tr[rc].fz; } void rotate(int x,int w) { int f=tr[x].f,ff=tr[f].f; int R,r; R=f;r=tr[x].son[w]; tr[R].son[1-w]=r; if(r!=0)tr[r].f=R; R=ff;r=x; if(tr[R].son[0]==f)tr[R].son[0]=r; else if(tr[R].son[1]==f)tr[R].son[1]=r; tr[r].f=R; R=x;r=f; tr[R].son[w]=r; tr[r].f=R; update(f); update(x); } bool isroot(int x) { if(tr[x].f!=0&&(tr[tr[x].f].son[0]==x||tr[tr[x].f].son[1]==x))return false; return true; } int tmp[210000]; void splay(int x,int rt) { int s=0,i=x; while(isroot(i)==false) { tmp[++s]=i; i=tr[i].f; } tmp[++s]=i; while(s!=0) { i=tmp[s];s--; if(tr[i].fz==true)reverse(i); } while(isroot(x)==false) { int f=tr[x].f,ff=tr[f].f; if(isroot(f)==true) { if(x==tr[f].son[0])rotate(x,1); else rotate(x,0); } else { if(tr[f].son[0]==x&&tr[ff].son[0]==f){rotate(f,1);rotate(x,1);} else if(tr[f].son[1]==x&&tr[ff].son[0]==f){rotate(x,0);rotate(x,1);} else if(tr[f].son[0]==x&&tr[ff].son[1]==f){rotate(x,1);rotate(x,0);} else if(tr[f].son[1]==x&&tr[ff].son[1]==f){rotate(f,0);rotate(x,0);} } } } //splay void access(int x) { int y=0; while(x!=0) { splay(x,0); tr[x].son[1]=y; if(y!=0)tr[y].f=x; update(x); y=x;x=tr[x].f; } } void makeroot(int x) { access(x);splay(x,0); tr[x].fz=1-tr[x].fz; } void Link(int x,int y) { makeroot(x);tr[x].f=y;access(x); } void Cut(int x,int y) { makeroot(x); access(y);splay(y,0); tr[tr[y].son[0]].f=0;tr[y].son[0]=0; update(y); } int findroot(int x) { access(x);splay(x,0); while(tr[x].son[0]!=0)x=tr[x].son[0]; return x; } //simple int getdis(int x,int y) { makeroot(x); access(y);splay(y,0); int ret=1; while(y!=x){y=tr[y].son[0];ret+=tr[tr[y].son[1]].c+1;} return ret; } //-------------------LCT------------------- bool intree[210000];//该边是否在树上 int main() { freopen("data.in","r",stdin); freopen("data.out","w",stdout); int n,m,T; scanf("%d%d%d",&n,&m,&T);yu(n); int st,ed; for(int i=1;i<=m;i++) { scanf("%d%d",&a[i].x,&a[i].y); scanf("%d%d",&st,&ed);st++;ed++; if(st>=ed){i--;m--;continue;} heap_st tt; tt.st=st, tt.ed=ed, tt.id=i; A.push(tt); } int tim=0; memset(intree,false,sizeof(intree)); for(int t=1;t<=T;t++) { while(B.empty()==false) { heap_ed h=B.top(); if(h.ed==t) { B.pop(); int k=h.id; if(intree[k]==true) { intree[k]=false; Cut(a[k].x,a[k].y); } } else break; } //----------结束时间到,删除树上边,非树上边可以直接无视,更新------- while(A.empty()==false) { heap_st h=A.top(); if(h.st==t) { A.pop(); heap_ed tt; tt.ed=h.ed, tt.id=h.id; B.push(tt); heap_mt uu; uu.ed=h.ed, uu.id=h.id; C.push(uu); } else break; } //----------起始时间到,将边入堆---------- while(C.empty()==false) { heap_mt h=C.top();C.pop(); if(h.ed<=t)break; int k=h.id; int x=a[k].x,y=a[k].y; if(x==y){tim=max(tim,h.ed-1);continue;} if(findroot(x)!=findroot(y)) { intree[k]=true; Link(x,y); } else { if(getdis(x,y)%2==1) tim=max(tim,h.ed-1); } } //----------将树边连满&&判奇环---------------- if(t<=tim)printf("No\n"); else printf("Yes\n"); } return 0; }
--------------------然而cdq+带权并查集搞出来了。。。-----------------------
感觉这个不算cdq分治,只是普通分治而已-_-! upd:这个东西其实叫线段树分治。。。。。
具体怎么做呢,就是类似线段树一样把每一时间段下放影响,这样可以保证对于当前这一段包含的边都是没消失的,然后假如遇到奇环就把当前区间全部设为false就行。
dis可以直接用异或代替,因为只是要判奇偶性,路径不用压缩,修改需要父亲,分治可以保证平衡。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<vector> using namespace std; int fa[210000],d[210000]; int findfa(int x) { while(x!=fa[x])x=fa[x]; return x; } int getdis(int x) { int dis=0; while(x!=fa[x])dis^=d[x],x=fa[x]; return dis; } //---------union-find sets------------- int top,sta[410000];bool v[410000]; int rak[210000]; void Link(int x,int y,int dis) { if(rak[x]>rak[y]) { top++; sta[top]=y,v[top]=true; fa[y]=x,d[y]=dis; } else if(rak[x]<rak[y]) { top++; sta[top]=x,v[top]=true; fa[x]=y,d[x]=dis; } else { rak[x]++;top++; sta[top]=y,v[top]=false; fa[y]=x,d[y]=dis; } } void Cut(int now) { while(now!=top) { int k=sta[top];top--; if(v[top+1]==false)rak[fa[k]]--; fa[k]=k, d[k]=0; } } //------------------玄学-------------------------------- struct edge{int x,y,st,ed;}; bool as[210000]; void cdq(int l,int r,vector<edge> hh) { int mid=(l+r)/2; vector<edge> ll,rr; int len=hh.size(),now=top; for(int i=0;i<len;i++) { edge e=hh[i]; if(e.st==l&&e.ed==r) { int x=e.x,y=e.y; int fx=findfa(x),fy=findfa(y); int dis=getdis(x)^getdis(y)^1; if(fx!=fy)Link(fx,fy,dis); else if((dis&1)>0) { for(int i=l;i<=r;i++)as[i]=false; Cut(now); return ; } } else if(e.ed<=mid) ll.push_back(e); else if(mid+1<=e.st)rr.push_back(e); else { edge lc,rc;lc=rc=e; lc.ed=mid;rc.st=mid+1; ll.push_back(lc); rr.push_back(rc); } } if(l==r)as[l]=true; else cdq(l,mid,ll), cdq(mid+1,r,rr); Cut(now); } vector<edge> S; int main() { int n,m,T; scanf("%d%d%d",&n,&m,&T); for(int i=1;i<=m;i++) { int x,y,st,ed; scanf("%d%d%d%d",&x,&y,&st,&ed); if(st>=ed)continue; st++; S.push_back((edge){x,y,st,ed}); } for(int i=1;i<=n;i++)fa[i]=i; memset(d,0,sizeof(d)); memset(rak,0,sizeof(rak)); top=0; cdq(1,T,S); for(int i=1;i<=T;i++) if(as[i]==true)printf("Yes\n"); else printf("No\n"); return 0; }
-------------------------------再一次upd----------------------------------------
学会了线段树分治就是傻子题了,只要上并查集判奇环即可
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<vector> using namespace std; struct edge{int x,y;}e[210000]; struct node { int l,r,lc,rc; vector<int>id,u; }tr[210000];int trlen; void bt(int l,int r) { int now=++trlen; tr[now].l=l;tr[now].r=r; tr[now].lc=tr[now].rc=-1; if(l<r) { int mid=(l+r)/2; tr[now].lc=trlen+1;bt(l,mid); tr[now].rc=trlen+1;bt(mid+1,r); } } void insert(int now,int l,int r,int p) { if(tr[now].l==l&&tr[now].r==r) { tr[now].id.push_back(p); return ; } int lc=tr[now].lc,rc=tr[now].rc; int mid=(tr[now].l+tr[now].r)/2; if(r<=mid) insert(lc,l,r,p); else if(mid+1<=l)insert(rc,l,r,p); else insert(lc,l,mid,p),insert(rc,mid+1,r,p); } //---------------------------------------init---------------------------------------------------- int fa[210000]; const int ot=101000; int findfa(int x) { if(fa[x]<0)return x; return findfa(fa[x]); } void merge(int now,bool &bk,int x,int y) { int fx1=findfa(x),fy2=findfa(y+ot); if(fx1!=fy2) { if(fa[fx1]>fa[fy2]) { tr[now].u.push_back(fx1); fa[fy2]+=fa[fx1]; fa[fx1]=fy2; } else { tr[now].u.push_back(fy2); fa[fx1]+=fa[fy2]; fa[fy2]=fx1; } } int fy1=findfa(y),fx2=findfa(x+ot); if(fx2!=fy1) { if(fa[fx2]>fa[fy1]) { tr[now].u.push_back(fx2); fa[fy1]+=fa[fx2]; fa[fx2]=fy1; } else { tr[now].u.push_back(fy1); fa[fx2]+=fa[fy1]; fa[fy1]=fx2; } } if(findfa(fx1)==findfa(fx2)||findfa(fy1)==findfa(fy2))bk=false; } struct Answer{int l,r;bool b;}as[110000];int tp; void dfs(int now) { bool bk=true; for(int i=0;i<tr[now].id.size();i++) merge(now,bk,e[tr[now].id[i]].x,e[tr[now].id[i]].y); if(bk==false) { as[++tp].l=tr[now].l,as[tp].r=tr[now].r,as[tp].b=false; } else { if(tr[now].l==tr[now].r)as[++tp].l=as[tp].r=tr[now].l,as[tp].b=true; else { dfs(tr[now].lc); dfs(tr[now].rc); } } for(int i=0;i<tr[now].u.size();i++) fa[tr[now].u[i]]=-1; } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int n,m,T,st,ed; scanf("%d%d%d",&n,&m,&T); trlen=0;bt(1,T); for(int i=1;i<=m;i++) { scanf("%d%d%d%d",&e[i].x,&e[i].y,&st,&ed); if(st>=ed){i--,m--;continue;} insert(1,st+1,ed,i); } memset(fa,-1,sizeof(fa)); tp=0;dfs(1); for(int i=1;i<=tp;i++) for(int j=as[i].l;j<=as[i].r;j++) if(as[i].b)printf("Yes\n"); else printf("No\n"); return 0; }
pain and happy in the cruel world.