bzoj3514: Codechef MARCH14 GERALD07加强版

地址:http://www.lydsy.com/JudgeOnline/problem.php?id=3514

题目:

3514: Codechef MARCH14 GERALD07加强版

Time Limit: 60 Sec  Memory Limit: 256 MB
Submit: 1822  Solved: 703
[Submit][Status][Discuss]

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。


2016.2.26提高时限至60s

 

Source

By zhonghaoxi

 

思路:

  想了二十分钟后果断滚去看题解了。

  有一个比较猎奇的做法:首先把边依次加到图中,若当前这条边与图中的边形成了环,那么把这个环中最早加进来的边弹出去
  并将每条边把哪条边弹了出去记录下来:ntr[i] = j,特别地,要是没有弹出边,ntr[i] = 0;
  这个显然是可以用LCT来弄的对吧。
  然后对于每个询问,我们的答案就是对l~r中ntr小于l的边求和,并用n减去这个值
  正确性可以YY一下:
  如果一条边的ntr >= l,那么显然他可以与从l ~ r中的边形成环,那么它对答案没有贡献
  反之如果一条边的ntr < l那么它与从l ~ r中的边是不能形成环的,那么他对答案的贡献为-1
  对于查询从l ~ r中有多少边的ntr小于l,我反正是用的函数式线段树

  lct+主席树,好神啊。

  主席树开200007*20居然re,说好的nlogn呢。

  1 /**************************************************************
  2     Problem: 3514
  3     User: weeping
  4     Language: C++
  5     Result: Accepted
  6     Time:45408 ms
  7     Memory:110692 kb
  8 ****************************************************************/
  9  
 10 #include <bits/stdc++.h>
 11  
 12 using namespace std;
 13  
 14 const int K = 300007 * 20;
 15  
 16 struct Link_Cut_Tree
 17 {
 18     static const int MAXN = 500000 + 7;
 19  
 20     int ch[MAXN][2], fa[MAXN], rev[MAXN], v[MAXN], mx[MAXN] ,id[MAXN];
 21     int sk[MAXN];
 22  
 23     bool isroot(int x)
 24     {
 25         return ch[fa[x]][0] != x && ch[fa[x]][1] != x;
 26     }
 27  
 28     void reverse(int x)
 29     {
 30         rev[x] ^= 1, swap(ch[x][0],ch[x][1]);
 31     }
 32  
 33     void update(int x)
 34     {
 35         int lc = ch[x][0], rc = ch[x][1];
 36         mx[x] = v[x], id[x] = x;
 37         if(lc&&mx[lc]<mx[x])
 38             mx[x] = mx[lc], id[x] = id[lc];
 39         if(rc&&mx[rc]<mx[x])
 40             mx[x] = mx[rc], id[x] = id[rc];
 41     }
 42  
 43     void push_down(int x)
 44     {
 45         if(!rev[x]) return ;
 46         if(ch[x][0]) reverse(ch[x][0]);
 47         if(ch[x][1]) reverse(ch[x][1]);
 48         rev[x]=0;
 49     }
 50  
 51     void rotate(int x)
 52     {
 53         int f = fa[x], gf = fa[f];
 54         int t1 = ( x != ch[f][0]), t2 = ( f != ch[gf][0]), tmp = ch[x][1^t1];
 55         if(!isroot(f)) ch[gf][0^t2] = x;
 56         fa[tmp] = f, fa[x] = gf, ch[x][1^t1] = f, fa[f] = x, ch[f][0^t1] = tmp;
 57         update(f);
 58     }
 59  
 60     void splay(int x)
 61     {
 62         int top = 0;
 63         sk[++top] = x;
 64         for(int i = x; !isroot(i); i = fa[i])   sk[++top] = fa[i];
 65         while(top)  push_down(sk[top--]);
 66         for(int f = fa[x], gf = fa[f]; !isroot(x); rotate(x), f = fa[x],gf = fa[f])
 67         if(!isroot(f))
 68             rotate((x==ch[f][0]) ^ (f==ch[gf][0]) ? x : f);
 69         update(x);
 70     }
 71  
 72     void access(int x)
 73     {
 74         for(int p = 0; x; p = x, x = fa[x])
 75             splay(x), ch[x][1] = p, update(x);
 76     }
 77  
 78     void makeroot(int x)
 79     {
 80         access(x), splay(x), reverse(x);
 81     }
 82  
 83     int findroot(int x)
 84     {
 85         access(x), splay(x);
 86         while(ch[x][0]) x = ch[x][0];
 87         return x;
 88     }
 89     void link(int x,int y)
 90     {
 91         makeroot(x), fa[x] = y;
 92     }
 93  
 94     void cut(int x,int y)
 95     {
 96         makeroot(x), access(y), splay(y);
 97         if(ch[y][0] == x)   ch[y][0] = fa[x] = 0;
 98         update(y);
 99     }
100  
101     int go(int u,int v,int n,int m,int k)
102     {
103         if(u==v)
104             return m+2;
105         if(findroot(u)!=findroot(v))
106         {
107             link(u,k+n),link(v,k+n);
108             return 1;
109         }
110         makeroot(u),access(v),splay(v);
111         int p = id[v];
112         splay(p);
113         fa[ch[p][0]] = fa[ch[p][1]] = 0;
114         ch[p][0] = ch[p][1] = 0;
115         link(u,k+n),link(v,k+n);
116         return p-n+1;
117     }
118 }lct;
119  
120  
121 int tot,ls[K],rs[K],rt[K],sum[K];
122  
123 void build(int &o,int l,int r)
124 {
125     o=++tot,sum[o]=0;
126     int mid=l+r>>1;
127     if(l!=r)
128         build(ls[o],l,mid),build(rs[o],mid+1,r);
129 }
130 void update(int &o,int l,int r,int last,int x)
131 {
132     o=++tot,sum[o]=sum[last]+1;
133     ls[o]=ls[last],rs[o]=rs[last];
134     if(l==r) return ;
135     int mid=l+r>>1;
136     if(x<=mid) update(ls[o],l,mid,ls[last],x);
137     else update(rs[o],mid+1,r,rs[last],x);
138 }
139 int query(int lo,int ro,int l,int r,int k)
140 {
141     if(r<=k) return sum[ro]-sum[lo];
142     if(l>k) return 0;
143     int mid=l+r>>1;
144     return query(ls[lo],ls[ro],l,mid,k) + query(rs[lo],rs[ro],mid+1,r,k);
145 }
146  
147 int main(void)
148 {
149     //freopen("in.acm","r",stdin);
150    int n,m,k,tp;
151    scanf("%d%d%d%d",&n,&m,&k,&tp);
152    for(int i=1;i<=n;i++)    lct.v[i] = lct.mx[i] = m + 2, lct.id[i] = i;
153    build(rt[0],1,m+2);
154    for(int i=1,x,y;i<=m;i++)
155    {
156        scanf("%d%d",&x,&y);
157        lct.v[i+n]=lct.mx[i+n]=i,lct.id[i+n]=i+n;
158        update(rt[i],1,m+2,rt[i-1],lct.go(x,y,n,m,i));;
159    }
160    int l,r,ls=0;
161    while(k--)
162    {
163        scanf("%d%d",&l,&r);
164        if(tp)   l^=ls,r^=ls;
165        ls=n-query(rt[l-1],rt[r],1,m+2,l);
166        printf("%d\n",ls);
167    }
168     return 0;
169 }

 

 

posted @ 2017-10-02 15:23  weeping  阅读(155)  评论(0编辑  收藏  举报