1. 程式人生 > >CodeForces gym Nasta Rabbara lct

CodeForces gym Nasta Rabbara lct

cond n) signed lin aps 等於 scan turn pair

Nasta Rabbara

題意:簡單來說就是, 現在有 n個點, m條邊, 每次詢問一個區間[ l , r ], 將這個區間的所有邊都連上, 如果現在的圖中有奇數環, 就輸出 “Impossible”, 否者就輸出 ”possible“。

題解:

步驟1:我們先找出每個最小的 [ l, r] 當這個區間的邊都出現後, 就會出現一個奇數環。

步驟2:問題就變成了對於一次詢問 [ L, R ] 是否存在上面的一個區間 被完全覆蓋。

對於步驟1來說:需要加邊和刪邊, 我們用 lct 維護。

我們按照 1 ... m 的順序, 進行添加邊。

如果 u 和 v 不聯通, 那麽我們直接將u和v連起來。

如果 u 和 v 聯通, 那麽如果我們加上這個邊之後就會形成環。

如果是偶數環, 那麽我們就刪除這個環上最先添加進來的邊, 因為我們需要找到最小的[l, r]奇數環區間。

如果是奇數環, 那麽說明我們已經找到了一個奇數環區間, 因為有偶數環刪除的保證, 所以我們找到的一定是最小的奇數環區間。

然後我們再刪除邊,將 l+1前面的邊都刪除, 繼續往下找下一個最小奇數環區間。

對於步驟2來說:

我們可以離線所有詢問。

對於所有的最小奇數環區間和詢問區間都按照左端點大的排序。

當詢問區間的 左端點的位置 <= 當前奇數環區間的時候,就在標記一下奇數環區間的右端, 用樹狀數組維護。

然後查詢詢問區間的右端點之前有沒有點出現過, 如果有就說明有區間被完全覆蓋。

因為添加到樹狀數組裏面的 奇數環區間 的左端點一定是 大或等於 當前區間左端點的。

最後輸出答案。

代碼:

技術分享圖片
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define Fopen freopen("2.in","r",stdin); freopen("_out.txt","w",stdout);
  4 #define LL long long
  5 #define ULL unsigned LL
  6 #define fi first
  7 #define se second
  8 #define pb push_back
  9
#define lson l,m,rt<<1 10 #define rson m+1,r,rt<<1|1 11 #define lch(x) tr[x].son[0] 12 #define rch(x) tr[x].son[1] 13 #define max3(a,b,c) max(a,max(b,c)) 14 #define min3(a,b,c) min(a,min(b,c)) 15 typedef pair<int,int> pll; 16 const int inf = 0x3f3f3f3f; 17 const LL INF = 0x3f3f3f3f3f3f3f3f; 18 const LL mod = (int)1e9+7; 19 const int N = 2e5 + 100; 20 struct Node{ 21 int rev, rt; 22 int son[2], pre; 23 int id, mn, sz; 24 void init(int t){ 25 sz = rt = 1; 26 rev = pre = son[0] = son[1] = 0; 27 id = mn = t; 28 } 29 }tr[N]; 30 void Push_Rev(int x){ 31 if(!x) return ; 32 swap(lch(x), rch(x)); 33 tr[x].rev ^= 1; 34 } 35 void Push_Up(int x){ 36 if(!x) return ; 37 tr[x].sz = tr[lch(x)].sz + tr[rch(x)].sz + 1; 38 tr[x].mn = min3(tr[lch(x)].mn, tr[rch(x)].mn, tr[x].id); 39 } 40 void Push_Down(int x){ 41 if(tr[x].rev){ 42 tr[x].rev = 0; 43 Push_Rev(lch(x)); 44 Push_Rev(rch(x)); 45 } 46 } 47 void Rev(int x){ 48 if(!tr[x].rt) Rev(tr[x].pre); 49 Push_Down(x); 50 } 51 void rotate(int x){ 52 if(tr[x].rt) return; 53 int y = tr[x].pre, z = tr[y].pre; 54 int k = (rch(y) == x); 55 tr[y].son[k] = tr[x].son[k^1]; 56 tr[tr[y].son[k]].pre = y; 57 tr[x].son[k^1] = y; 58 tr[y].pre = x; 59 tr[x].pre = z; 60 if(tr[y].rt) tr[y].rt = 0, tr[x].rt = 1; 61 else tr[z].son[rch(z) == y] = x; 62 Push_Up(y); 63 } 64 void Splay(int x){ 65 Rev(x); 66 while(!tr[x].rt){ 67 int y = tr[x].pre, z = tr[y].pre; 68 if(!tr[y].rt){ 69 if(( x == rch(y) ) != (y == rch(z))) rotate(y); 70 else rotate(x); 71 } 72 rotate(x); 73 } 74 Push_Up(x); 75 } 76 void Access(int x){ 77 int y = 0; 78 do{ 79 Splay(x); 80 tr[rch(x)].rt = 1; 81 rch(x) = y; 82 tr[y].rt = 0; 83 Push_Up(x); 84 y = x; 85 x = tr[x].pre; 86 }while(x); 87 } 88 void Make_rt(int x){ 89 Access(x); 90 Splay(x); 91 Push_Rev(x); 92 } 93 void link(int u, int v){ 94 Make_rt(u); 95 tr[u].pre = v; 96 } 97 void cut(int u, int v){ 98 Make_rt(u); 99 Access(v); 100 Splay(v); 101 tr[lch(v)].pre = 0; 102 tr[lch(v)].rt = 1; 103 tr[v].pre = 0; 104 lch(v) = 0; 105 } 106 bool judge(int u, int v){ 107 while(tr[u].pre) u = tr[u].pre; 108 while(tr[v].pre) v = tr[v].pre; 109 return u == v; 110 } 111 int x[N], y[N]; 112 int l[N], r[N]; 113 int in[N]; 114 int ans[N]; 115 int tot = 0; 116 int n, m, q; 117 struct node{ 118 int l, r, id; 119 bool operator < (const node & x) const { 120 return l > x.l; 121 } 122 }A[N]; 123 void solve(int st, int ed){ 124 for(int i = st; i <= ed; i++){ 125 if(!in[i]) continue; 126 cut(x[i], i+n); 127 cut(y[i], i+n); 128 in[i] = 0; 129 } 130 } 131 int tree[N]; 132 inline int lowbit(int x){ 133 return x & (-x); 134 } 135 int Query(int x){ 136 int ret = 0; 137 while(x){ 138 ret += tree[x]; 139 x -= lowbit(x); 140 } 141 return ret; 142 } 143 void Add(int x){ 144 while(x <= m){ 145 tree[x]++; 146 x += lowbit(x); 147 } 148 } 149 int main(){ 150 scanf("%d%d%d", &n, &m, &q); 151 for(int i = 1; i <= n; i++) tr[i].init(inf); 152 tr[0].mn = tr[0].id = inf; 153 for(int i = 1; i <= m; i++){ 154 scanf("%d%d", &x[i], &y[i]); 155 tr[i+n].init(i+n); 156 } 157 int b = 1; 158 for(int i = 1; i <= m; i++){ 159 int u = x[i], v = y[i], id = n+i; 160 if(!judge(u, v)){ 161 link(u, id); 162 link(v, id); 163 in[i] = 1; 164 } 165 else { 166 Make_rt(u); 167 Access(v); 168 Splay(v); 169 int sz = tr[v].sz/2; 170 int t = tr[v].mn; 171 if(sz&1) { 172 cut(u, t); 173 cut(v, t); 174 in[t-n] = 0; 175 } 176 else { 177 l[++tot] = t-n; r[tot] = i; 178 solve(b, t-n); 179 b = t-n; 180 } 181 link(u, id); 182 link(v, id); 183 in[i] = 1; 184 } 185 } 186 for(int i = 1; i <= q; i++){ 187 scanf("%d%d", &A[i].l, &A[i].r); 188 A[i].id = i; 189 } 190 sort(A+1, A+1+q); 191 for(int i = 1; i <= q; i++){ 192 int ll = A[i].l, rr = A[i].r, id = A[i].id; 193 while(tot && ll <= l[tot]){ 194 Add(r[tot]); 195 tot--; 196 } 197 if(Query(rr)) ans[id] = 1; 198 } 199 for(int i = 1; i <= q; i++){ 200 if(ans[i]) puts("Impossible"); 201 else puts("Possible"); 202 } 203 return 0; 204 }
View Code

因為一直在實驗室問步驟2的問題, 又聽到一個別的思路。

因為我們保證了最小奇數環區間是沒有覆蓋情況的, 我們按照左端點小的排序。

對於每次詢問我們找到第一段左端點大於詢問區間的左端點的區間, 然後判斷一下右端點是不是在這個區間裏面就好了。

代碼:

技術分享圖片
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define Fopen freopen("2.in","r",stdin); freopen("_out.txt","w",stdout);
  4 #define LL long long
  5 #define ULL unsigned LL
  6 #define fi first
  7 #define se second
  8 #define pb push_back
  9 #define lson l,m,rt<<1
 10 #define rson m+1,r,rt<<1|1
 11 #define lch(x) tr[x].son[0]
 12 #define rch(x) tr[x].son[1]
 13 #define max3(a,b,c) max(a,max(b,c))
 14 #define min3(a,b,c) min(a,min(b,c))
 15 typedef pair<int,int> pll;
 16 const int inf = 0x3f3f3f3f;
 17 const LL INF = 0x3f3f3f3f3f3f3f3f;
 18 const LL mod =  (int)1e9+7;
 19 const int N = 2e5 + 100;
 20 struct Node{
 21     int rev, rt;
 22     int son[2], pre;
 23     int id, mn, sz;
 24     void init(int t){
 25         sz = rt = 1;
 26         rev = pre = son[0] = son[1] = 0;
 27         id = mn = t;
 28     }
 29 }tr[N];
 30 void Push_Rev(int x){
 31     if(!x) return ;
 32     swap(lch(x), rch(x));
 33     tr[x].rev ^= 1;
 34 }
 35 void Push_Up(int x){
 36     if(!x) return ;
 37     tr[x].sz = tr[lch(x)].sz + tr[rch(x)].sz + 1;
 38     tr[x].mn = min3(tr[lch(x)].mn, tr[rch(x)].mn, tr[x].id);
 39 }
 40 void Push_Down(int x){
 41    if(tr[x].rev){
 42         tr[x].rev = 0;
 43         Push_Rev(lch(x));
 44         Push_Rev(rch(x));
 45     }
 46 }
 47 void Rev(int x){
 48     if(!tr[x].rt) Rev(tr[x].pre);
 49     Push_Down(x);
 50 }
 51 void rotate(int x){
 52     if(tr[x].rt) return;
 53     int y = tr[x].pre, z = tr[y].pre;
 54     int k = (rch(y) == x);
 55     tr[y].son[k] = tr[x].son[k^1];
 56     tr[tr[y].son[k]].pre = y;
 57     tr[x].son[k^1] = y;
 58     tr[y].pre = x;
 59     tr[x].pre = z;
 60     if(tr[y].rt) tr[y].rt = 0, tr[x].rt = 1;
 61     else tr[z].son[rch(z) == y] = x;
 62     Push_Up(y);
 63 }
 64 void Splay(int x){
 65      Rev(x);
 66      while(!tr[x].rt){
 67         int y = tr[x].pre, z = tr[y].pre;
 68         if(!tr[y].rt){
 69             if(( x == rch(y) ) != (y == rch(z))) rotate(y);
 70             else rotate(x);
 71         }
 72         rotate(x);
 73     }
 74     Push_Up(x);
 75 }
 76 void Access(int x){
 77     int y = 0;
 78     do{
 79         Splay(x);
 80         tr[rch(x)].rt = 1;
 81         rch(x) = y;
 82         tr[y].rt = 0;
 83         Push_Up(x);
 84         y = x;
 85         x = tr[x].pre;
 86     }while(x);
 87 }
 88 void Make_rt(int x){
 89     Access(x);
 90     Splay(x);
 91     Push_Rev(x);
 92 }
 93 void link(int u, int v){
 94     Make_rt(u);
 95     tr[u].pre = v;
 96 }
 97 void cut(int u, int v){
 98     Make_rt(u);
 99     Access(v);
100     Splay(v);
101     tr[lch(v)].pre = 0;
102     tr[lch(v)].rt = 1;
103     tr[v].pre = 0;
104     lch(v) = 0;
105 }
106 bool judge(int u, int v){
107     while(tr[u].pre) u = tr[u].pre;
108     while(tr[v].pre) v = tr[v].pre;
109     return u == v;
110 }
111 int x[N], y[N];
112 int in[N];
113 int ans[N];
114 int tot = 0;
115 pll P[N];
116 int n, m, q;
117 void solve(int st, int ed){
118     for(int i = st; i <= ed; i++){
119         if(!in[i]) continue;
120         cut(x[i], i+n);
121         cut(y[i], i+n);
122         in[i] = 0;
123     }
124 }
125 int main(){
126     scanf("%d%d%d", &n, &m, &q);
127     for(int i = 1; i <= n; i++) tr[i].init(inf);
128     tr[0].mn = tr[0].id = inf;
129     for(int i = 1; i <= m; i++){
130         scanf("%d%d", &x[i], &y[i]);
131         tr[i+n].init(i+n);
132     }
133     int b = 1;
134     for(int i = 1; i <= m; i++){
135         int u = x[i], v = y[i], id = n+i;
136         if(!judge(u, v)){
137             link(u, id);
138             link(v, id);
139             in[i] = 1;
140         }
141         else {
142             Make_rt(u);
143             Access(v);
144             Splay(v);
145             int sz = tr[v].sz/2;
146             int t = tr[v].mn;
147             if(sz&1) {
148                 cut(u, t);
149                 cut(v, t);
150                 in[t-n] = 0;
151             }
152             else {
153                 P[tot].fi = t-n; P[tot++].se = i;
154 
155                 solve(b, t-n);
156                 b = t-n;
157             }
158             link(u, id);
159             link(v, id);
160             in[i] = 1;
161         }
162     }
163     int l, r;
164     for(int i = 1; i <= q; i++){
165         scanf("%d%d", &l, &r);
166         int p = upper_bound(P, P+tot, pll(l,-1)) - P;
167         if(p == tot || r < P[p].se) puts("Possible");
168         else puts("Impossible");
169     }
170     return 0;
171 }
View Code

CodeForces gym Nasta Rabbara lct