BZOJ3514:GERALD07加强版(LCT,主席树)

Description

N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。

Input

第一行四个整数N、M、K、type,代表点数、边数、询问数以及询问是否加密。
接下来M行,代表图中的每条边。
接下来K行,每行两个整数L、R代表一组询问。对于type=0的测试点,读入的L和R即为询问的L、R;对于type=1的测试点,每组询问的L、R应为L xor lastans和R xor lastans。

Output

 K行每行一个整数代表该组询问的联通块个数。

Sample Input

3 5 4 0
1 3
1 2
2 1
3 2
2 2
2 3
1 5
5 5
1 2

Sample Output

2
1
3
1

HINT

对于100%的数据,1≤N、M、K≤200,000。

Solution

$namespace$真是个好东西QAQ

每次往里加边,如果构成环的话就把最早的那条边删掉,这个可以用$LCT$随便做。

定义一个数组$Early[i]$,表示加第$i$条边的时候,会把哪条边删掉。

特殊的,如果不删边,$Early[i]=0$。如果第$i$条边是自环,$Early[i]=i$。

然后对$Early$数组建主席树,每次询问的答案就是$[l,r]$区间内小于等于$l-1$的数个个数。

正确性……如果一条边$i$的$Early[i]$在$l$后面的话,那么加入$i$的时候,因为会产生环所以不会对连通块情况产生影响。否则如果$Early[i]$在$l$的前面的话,加入$i$就会对连通块情况产生影响……

大体就是这样子具体我也不会

Code

  1 #include<iostream>
  2 #include<cstdio>
  3 #define N (400009)
  4 using namespace std;
  5 
  6 int n,m,k,opt,Early[N],x[N],y[N];
  7 
  8 namespace LCT
  9 {
 10     int Father[N],Son[N][2],Val[N],Min[N],Rev[N];
 11 
 12     int Get(int x)
 13     {
 14         return Son[Father[x]][1]==x;
 15     }
 16     int Is_root(int x)
 17     {
 18         return Son[Father[x]][0]!=x && Son[Father[x]][1]!=x;
 19     }
 20     void Pushup(int x)
 21     {
 22         Min[x]=x;
 23         int ls=Son[x][0],rs=Son[x][1];
 24         if (Val[Min[ls]]<Val[Min[x]]) Min[x]=Min[ls];
 25         if (Val[Min[rs]]<Val[Min[x]]) Min[x]=Min[rs];
 26     }
 27     void Pushdown(int x)
 28     {
 29         if (Rev[x])
 30         {
 31             Rev[Son[x][0]]^=1;
 32             Rev[Son[x][1]]^=1;
 33             swap(Son[x][0],Son[x][1]);
 34             Rev[x]=0;
 35         }
 36     }
 37     void Rotate(int x)
 38     {
 39         int wh=Get(x);
 40         int fa=Father[x],fafa=Father[fa];
 41         if (!Is_root(fa)) Son[fafa][Son[fafa][1]==fa]=x;
 42         Father[fa]=x; Son[fa][wh]=Son[x][wh^1];
 43         if (Son[fa][wh]) Father[Son[fa][wh]]=fa;
 44         Father[x]=fafa; Son[x][wh^1]=fa;
 45         Pushup(fa); Pushup(x);
 46     }
 47     void Push(int x)
 48     {
 49         if (!Is_root(x)) Push(Father[x]);
 50         Pushdown(x);
 51     }
 52     void Splay(int x)
 53     {
 54         Push(x);
 55         for (int fa; !Is_root(x); Rotate(x))
 56             if (!Is_root(fa=Father[x]))
 57                 Rotate(Get(fa)==Get(x)?fa:x);
 58     }
 59     void Access(int x)
 60     {
 61         for (int y=0; x; y=x,x=Father[x])
 62             Splay(x), Son[x][1]=y, Pushup(x);
 63     }
 64     void Make_root(int x)
 65     {
 66         Access(x); Splay(x); Rev[x]^=1;
 67     }
 68     int Find_root(int x)
 69     {
 70         Access(x); Splay(x);
 71         while (Son[x][0]) x=Son[x][0];
 72         return x;
 73     }
 74     void Link(int x,int y)
 75     {
 76         Make_root(x); Father[x]=y;
 77     }
 78     void Cut(int x,int y)
 79     {
 80         Make_root(x); Access(y); Splay(y);
 81         Son[y][0]=Father[x]=0; Pushup(y);
 82     }
 83     int Query(int x,int y)
 84     {
 85         Make_root(x); Access(y); Splay(y);
 86         return Min[y];
 87     }
 88     void Build_Early()
 89     {
 90         for (int i=1; i<=m; ++i) Val[n+i]=i;
 91         for (int i=0; i<=n; ++i) Val[i]=2e8,Min[i]=i;
 92         for (int i=1; i<=m; ++i)
 93         {
 94             scanf("%d%d",&x[i],&y[i]);
 95             if (x[i]==y[i]) {Early[i]=i; continue;}
 96             if (Find_root(x[i])!=Find_root(y[i]))
 97                 Link(x[i],i+n), Link(y[i],i+n);
 98             else
 99             {
100                 int p=Query(x[i],y[i]);
101                 Early[i]=p-n;
102                 Cut(x[p-n],p); Cut(y[p-n],p);
103                 Link(x[i],i+n); Link(y[i],i+n);
104             }
105         }
106     }
107 }
108 
109 namespace Sgt
110 {
111     struct Sgt{int ls,rs,val;}Segt[N*40];
112     int sgt_num,Root[N];
113 
114     int Update(int pre,int l,int r,int x)
115     {
116         int now=++sgt_num;
117         Segt[now]=Segt[pre];
118         Segt[now].val++;
119         if (l==r) return now;
120         int mid=(l+r)>>1;
121         if (x<=mid) Segt[now].ls=Update(Segt[now].ls,l,mid,x);
122         else Segt[now].rs=Update(Segt[now].rs,mid+1,r,x);
123         return now;
124     }
125     int Query(int u,int v,int l,int r,int l1,int r1)
126     {
127         if (l>r1 || r<l1) return 0;
128         if (l1<=l && r<=r1) return Segt[v].val-Segt[u].val;
129         int mid=(l+r)>>1;
130         return Query(Segt[u].ls,Segt[v].ls,l,mid,l1,r1)+Query(Segt[u].rs,Segt[v].rs,mid+1,r,l1,r1);
131     }
132     void Solve()
133     {
134         for (int i=1; i<=m; ++i)
135             Root[i]=Update(Root[i-1],0,2e5,Early[i]);
136         int ans=0,l,r;
137         for (int i=1; i<=k; ++i)
138         {
139             scanf("%d%d",&l,&r);
140             if (opt) l^=ans, r^=ans;
141             ans=n-Query(Root[l-1],Root[r],0,2e5,0,l-1);
142             printf("%d\n",ans);
143         }
144     }
145 }
146 
147 int main()
148 {
149     scanf("%d%d%d%d",&n,&m,&k,&opt);
150     LCT::Build_Early();
151     Sgt::Solve();
152 }
posted @ 2018-12-08 20:12  Refun  阅读(219)  评论(0编辑  收藏  举报