【BZOJ3514】Codechef MARCH14 GERALD07加强版 LCT+主席树
【BZOJ3514】Codechef MARCH14 GERALD07加強版
Description
N個點M條邊的無向圖,詢問保留圖中編號在[l,r]的邊的時候圖中的聯(lián)通塊個數(shù)。
Input
第一行四個整數(shù)N、M、K、type,代表點數(shù)、邊數(shù)、詢問數(shù)以及詢問是否加密。
接下來M行,代表圖中的每條邊。
接下來K行,每行兩個整數(shù)L、R代表一組詢問。對于type=0的測試點,讀入的L和R即為詢問的L、R;對于type=1的測試點,每組詢問的L、R應(yīng)為L xor lastans和R xor lastans。
Output
?K行每行一個整數(shù)代表該組詢問的聯(lián)通塊個數(shù)。
Sample Input
3 5 4 01 3
1 2
2 1
3 2
2 2
2 3
1 5
5 5
1 2
Sample Output
21
3
1
HINT
對于100%的數(shù)據(jù),1≤N、M、K≤200,000。
題解:本題思路很神~
我們將邊按編號一條一條地加到圖中,如果當前邊a,b所在的連通塊已經(jīng)連通,則我們找到這個連通塊中編號最小的邊,記錄它的編號kick[i],并將它刪去,然后將當前邊加入到圖中。這個可以用LCT很容易的實現(xiàn)。(套路:用LCT維護邊權(quán)的方法,將邊變成點,a-b連邊視為a-c-b連邊,然后圖中只有從邊變過來的點才有權(quán)值)
然后采用主席樹,在i的主席樹中將kick[i]刪除,然后查詢[l,r]時再r的主席樹中查詢[l,r]這段區(qū)間,就能得到區(qū)間中有多少樹邊了。
?
#include <cstdio> #include <cstring> #include <iostream> using namespace std; const int maxn=200010; int n,m,Q,typ,tot,ans; int pa[maxn],pb[maxn],f[maxn],rt[maxn],sum[maxn]; struct LCT {int ch[2],fa,rev,mn,val; }t[maxn<<1]; struct sag {int ls,rs,siz; }s[maxn*40]; inline bool isr(int x) {return t[t[x].fa].ch[0]!=x&&t[t[x].fa].ch[1]!=x;} inline void rever(int x) {swap(t[x].ch[0],t[x].ch[1]),t[x].rev^=1; } inline void pushdown(int x) {if(t[x].rev){if(t[x].ch[0]) rever(t[x].ch[0]);if(t[x].ch[1]) rever(t[x].ch[1]);t[x].rev=0;} } inline void pushup(int x) {t[x].mn=min(t[x].val,min(t[t[x].ch[0]].mn,t[t[x].ch[1]].mn)); } inline void rotate(int x) {int y=t[x].fa,z=t[y].fa,d=(x==t[y].ch[1]);if(!isr(y)) t[z].ch[y==t[z].ch[1]]=x;t[x].fa=z,t[y].fa=x,t[y].ch[d]=t[x].ch[d^1];if(t[x].ch[d^1]) t[t[x].ch[d^1]].fa=y;t[x].ch[d^1]=y;pushup(y),pushup(x); } void updata(int x) {if(!isr(x)) updata(t[x].fa);pushdown(x); } inline void splay(int x) {updata(x);while(!isr(x)){int y=t[x].fa,z=t[y].fa;if(!isr(y)){if((x==t[y].ch[1])^(y==t[z].ch[1])) rotate(x);else rotate(y);}rotate(x);} } inline void access(int x) {for(int y=0;x;splay(x),t[x].ch[1]=y,pushup(x),y=x,x=t[x].fa); } inline void maker(int x) {access(x),splay(x),rever(x); } inline void link(int a,int b) {maker(a),t[a].fa=b; } inline void cut(int a,int b) {maker(a),access(b),splay(b),t[a].fa=t[b].ch[0]=0,pushup(b); } void insert(int x,int &y,int l,int r,int a,int b) {y=++tot,s[y].siz=s[x].siz+1;if(l==r) return ;int mid=(l+r)>>1;if(a<=mid) s[y].rs=s[x].rs,insert(s[x].ls,s[y].ls,l,mid,a,b);else s[y].ls=s[x].ls,insert(s[x].rs,s[y].rs,mid+1,r,a,b); } int query(int x,int l,int r,int a,int b) {if(!x||(a<=l&&r<=b)) return s[x].siz;int mid=(l+r)>>1;if(b<=mid) return query(s[x].ls,l,mid,a,b);if(a>mid) return query(s[x].rs,mid+1,r,a,b);return query(s[x].ls,l,mid,a,b)+query(s[x].rs,mid+1,r,a,b); } int find(int x) {return (f[x]==x)?x:(f[x]=find(f[x])); } inline int rd() {int ret=0,f=1; char gc=getchar();while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();return ret*f; } int main() {n=rd(),m=rd(),Q=rd(),typ=rd();int i,a,b,c;for(i=0;i<=n;i++) f[i]=i,t[i].val=t[i].mn=m+1;for(i=1;i<=m;i++) t[i+n].val=t[i+n].mn=i;for(i=1;i<=m;i++){a=pa[i]=rd(),b=pb[i]=rd(),sum[i]=sum[i-1]+1;if(a==b) sum[i]--,rt[i]=rt[i-1];else if(find(a)==find(b)){maker(a),access(b),splay(b),c=t[b].mn;insert(rt[i-1],rt[i],1,m,c,1);cut(pa[c],c+n),cut(pb[c],c+n),link(a,i+n),link(b,i+n);}else f[f[a]]=f[b],link(a,i+n),link(b,i+n),rt[i]=rt[i-1];}for(i=1;i<=Q;i++){a=rd()^(ans*typ),b=rd()^(ans*typ);ans=n-(sum[b]-sum[a-1]-query(rt[b],1,m,a,b));printf("%d\n",ans);}return 0; }//3 5 4 0 1 3 1 2 2 1 3 2 2 2 2 3 1 5 5 5 1 2?
轉(zhuǎn)載于:https://www.cnblogs.com/CQzhangyu/p/7670107.html
總結(jié)
以上是生活随笔為你收集整理的【BZOJ3514】Codechef MARCH14 GERALD07加强版 LCT+主席树的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 正确使用ViewStub
- 下一篇: 程序员转实施工程师_实施工程师到底做什么