1.bzoj 2002 弹飞绵羊
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN (200000+5)
struct LCT{
int fa[MAXN], ch[MAXN][2], size[MAXN];
bool isroot(int o){
return (o != ch[fa[o]][0] && o != ch[fa[o]][1]);
}
void push_up(int o){
int lc = ch[o][0], rc = ch[o][1];
size[o] = 1;
if(lc) size[o] += size[lc];
if(rc) size[o] += size[rc];
}
void rotate(int o){
int f = fa[o], g = fa[f];
int c = o == ch[f][1];
if(!isroot(f)){
if(ch[g][0] == f) ch[g][0] = o;
else if(ch[g][1] == f) ch[g][1] = o;
}
fa[f] = o; fa[o] = g;
fa[ch[o][c^1]] = f;
ch[f][c] = ch[o][c^1];
ch[o][c^1] = f;
push_up(f);
}
void splay(int o){
while(!isroot(o)){
int f = fa[o], g = fa[f];
if(isroot(f)){
rotate(o);
break;
}
if(!isroot(g)) rotate(f);
rotate(o);
}
push_up(o);
}
void access(int o){
int c = 0;
while(o){
splay(o);
ch[o][1] = c;
push_up(o);
c = o;
o = fa[o];
}
}
void cut(int v){
access(v);
splay(v);
fa[ch[v][0]] = 0;
ch[v][0] = 0;
push_up(v);
}
void link(int v, int w){
cut(v);
fa[v] = w;
}
};
LCT SP;
int main(){
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++){
int bon;
scanf("%d", &bon);
SP.fa[i] = (i+bon) > n? 0: (i+bon);
SP.size[i] = 1;
}
SP.size[0] = 0;
int m;
scanf("%d", &m);
for(int i = 1; i <= m; i++){
int op, j;
scanf("%d%d", &op, &j);
j++;
if(op == 1){
SP.access(j);
SP.splay(j);
printf("%d\n", SP.size[SP.ch[j][0]]+1);
}else{
int k;
scanf("%d", &k);
if(j+k > n) SP.link(j, 0);
else SP.link(j, j+k);
}
}
return 0;
}
2.bzoj 2049
洞穴勘测
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<stack>
using namespace std;
#define MAXN (10000+5)
int fa[MAXN], c[MAXN][2];
bool rev[MAXN];
void push_down(int x){
int l = c[x][0], r = c[x][1];
if(rev[x]){
rev[x] ^= 1; rev[l] ^= 1; rev[r] ^= 1;
swap(c[x][0], c[x][1]);
}
}
bool isroot(int x){
return (c[fa[x]][0] != x && c[fa[x]][1] != x);
}
void rotate(int o, int k){
int son = c[o][k], f = fa[o], grand = fa[f];
if(!isroot(f)){
if(c[grand][0] == f) c[grand][0] = o;
else c[grand][1] = o;
}
fa[o] = grand; fa[f] = o;
fa[son] = f;
c[f][k^1] = son;
c[o][k] = f;
}
void splay(int x){
stack<int> st;
st.push(x);
for(int i = x; !isroot(i); i = fa[i]) st.push(fa[i]);
while(!st.empty()) push_down(st.top()), st.pop();
while(!isroot(x)){
if(x == c[fa[x]][0]) rotate(x, 1);
else rotate(x, 0);
}
}
void access(int x){
int y = 0;
while(x){
splay(x);
c[x][1] = y;
y = x;
x = fa[x];
}
}
void rever(int x){
access(x); splay(x); rev[x] ^= 1;
}
void cut(int x, int y){
rever(x); access(y);
splay(y);
c[y][0] = fa[x] = 0;
}
void link(int x, int y){
rever(x); fa[x] = y;
}
int find(int x){
access(x); splay(x);
while(c[x][0]) x = c[x][0];
return x;
}
int main(){
char r[10];
int n, m;
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i++){
int u, v;
scanf("%s%d%d", r, &u, &v);
if(r[0] == 'C') link(u, v);
else if(r[0] == 'D') cut(u, v);
else{
int x = find(u), y = find(v);
if(x == y) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}
3.zjoi 2012 网络
题目描述
有一个无向图G,每个点有个权值,每条边有一个颜色。这个无向图满足以下两个条件:
-
对于任意节点连出去的边中,相同颜色的边不超过两条。
- 图中不存在同色的环,同色的环指相同颜色的边构成的环。
在这个图上,你要支持以下三种操作:
-
修改一个节点的权值。
-
修改一条边的颜色。
- 查询由颜色c的边构成的图中,所有可能在节点u到节点v之间的简单路径上的节点的权值的最大值。
输入输出格式
输入格式:输入文件network.in的第一行包含四个正整数N, M, C, K,其中N为节点个数,M为边数,C为边的颜色数,K为操作数。
接下来N行,每行一个正整数vi,为节点i的权值。
之后M行,每行三个正整数u, v, w,为一条连接节点u和节点v的边,颜色为w。满足1 ≤ u, v ≤ N,0 ≤ w < C,保证u ≠ v,且任意两个节点之间最多存在一条边(无论颜色)。
最后K行,每行表示一个操作。每行的第一个整数k表示操作类型。
-
k = 0为修改节点权值操作,之后两个正整数x和y,表示将节点x的权值vx修改为y。
-
k = 1为修改边的颜色操作,之后三个正整数u, v和w,表示将连接节点u和节点v的边的颜色修改为颜色w。满足0 ≤ w < C。
- k = 2为查询操作,之后三个正整数c, u和v,表示查询所有可能在节点u到节点v之间的由颜色c构成的简单路径上的节点的权值的最大值。如果不存在u和v之间不存在由颜色c构成的路径,那么输出“-1”。
输出文件network.out包含若干行,每行输出一个对应的信息。
-
对于修改节点权值操作,不需要输出信息。
- 对于修改边的颜色操作,按以下几类输出:
a) 若不存在连接节点u和节点v的边,输出“No such edge.”。
b) 若修改后不满足条件1,不修改边的颜色,并输出“Error 1.”。
c) 若修改后不满足条件2,不修改边的颜色,并输出“Error 2.”。
d) 其他情况,成功修改边的颜色,并输出“Success.”。
输出满足条件的第一条信息即可,即若同时满足b和c,则只需要输出“Error 1.”。
- 对于查询操作,直接输出一个整数。
输入输出样例
4 5 2 7
1
2
3
4
1 2 0
1 3 1
2 3 0
2 4 1
3 4 0
2 0 1 4
1 1 2 1
1 4 3 1
2 0 1 4
1 2 3 1
0 2 5
2 1 1 4
4
Success.
Error 2.
-1
Error 1.
5
说明
颜色0为实线的边,颜色1为虚线的边,
由颜色0构成的从节点1到节点4的路径有1 – 2 – 4,故max{v1, v2, v4} = max{ 1, 2, 4 } = 4。
将连接节点1和节点2的边修改为颜色1,修改成功,输出“Success.”
将连接节点4和节点3的边修改为颜色1,由于修改后会使得存在由颜色1构成的环( 1 – 2 – 4 – 3 – 1 ),不满足条件2,故不修改,并输出“Error 2”。
不存在颜色0构成的从节点1到节点4的边,输出“-1”。
将连接节点2和节点3的边修改为颜色1,由于修改后节点2的连出去的颜色为1的边有3条,故不满足条件1,故不修改,并输出“Error 1.”。
将节点2的权值修改为5。
由颜色1构成的从节点1到节点4的路径有 1 – 2 – 4,故max{v1, v2, v4} = max{ 1, 5, 4 } = 5。
【数据规模】
对于30%的数据:N ≤ 1000,M ≤ 10000,C ≤ 10,K ≤ 1000。
另有20%的数据:N ≤ 10000,M ≤ 100000,C = 1,K ≤ 100000。
对于100%的数据:N ≤ 10000,M ≤ 100000,C ≤ 10,K ≤ 100000。
本题的splay做法(已做),段大神的blog^-^: 点这里!!!
here is my LCT:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
#define LL long long
#define pb push_back
#define Set(a, v) memset(a, v, sizeof(a))
#define For(i, a, b) for(int i = (a); i <= (int)(b); i++)
#define Forr(i, a, b) for(int i = (a); i >= (int)(b); i--)
#define MAXN (10000+5)
#define MAXM (100000+5)
#define MAXC (10+5)
void read(int &x){
char ch = getchar();
while(ch < '0' || ch > '9') ch = getchar();
x = 0;
while(ch >= '0' && ch <= '9'){
x = x*10 + ch -'0';
ch = getchar();
}
}
int val[MAXN], st[MAXN], top;
struct LCT{
int ch[MAXN][2], fa[MAXN];
int maxv[MAXN], rev[MAXN], du[MAXN];
inline void maintain(int now){
maxv[now] = val[now];
if(ch[now][0]) maxv[now] = max(maxv[now], maxv[ch[now][0]]);
if(ch[now][1]) maxv[now] = max(maxv[now], maxv[ch[now][1]]);
}
inline void push_down(int o){
if(!rev[o]) return;
int &lc = ch[o][0], &rc = ch[o][1];
rev[lc] ^= 1; rev[rc] ^= 1; rev[o] ^= 1;
swap(lc, rc);
}
inline bool isroot(int o){
return (o != ch[fa[o]][0] && o != ch[fa[o]][1]);
}
inline void rotate(int o){
int f = fa[o], g = fa[f];
int c = (o == ch[f][1]);
if(!isroot(f)){
if(ch[g][0] == f) ch[g][0] = o;
else ch[g][1] = o;
}
fa[f] = o; fa[o] = g;
fa[ch[o][c^1]] = f;
ch[f][c] = ch[o][c^1]; ch[o][c^1] = f;
maintain(f);
}
inline void splay(int x){
top = 0;
st[++top] = x;
for(int i = x; !isroot(i); i = fa[i]) st[++top] = fa[i];
while(top){
push_down(st[top]); top--;
}
int o = x;
while(!isroot(o)){
int f = fa[o], g = fa[f];
if(isroot(f)){
rotate(o);
break;
}
if(!isroot(g)) rotate(f);
rotate(o);
}
maintain(o);
}
inline void access(int x){
int y = 0;
while(x){
splay(x);
ch[x][1] = y;
maintain(x);
y = x;
x = fa[x];
}
}
inline void rever(int x){
access(x); splay(x); rev[x] ^= 1;
}
inline void link(int x, int y){
du[x]++; du[y]++;
rever(x); fa[x] = y;
}
inline void cut(int x, int y){
du[x]--; du[y]--;
rever(x); access(y); splay(y);
ch[y][0] = fa[x] = 0;
maintain(y);
}
inline int find(int x){
access(x); splay(x);
int ret = x;
while(ch[ret][0]) ret = ch[ret][0];
return ret;
}
inline int query(int x, int y){
rever(x); access(y); splay(y);
return maxv[y];
}
};
struct UV{
int u, v;
bool operator <(const UV &rhs)const{
if(u != rhs.u) return u < rhs.u;
return v < rhs.v;
}
};
LCT lcts[MAXC];
map<UV, int> ms;
int main(){
int n, m, c, k, u, v, w, op, x;
read(n); read(m); read(c); read(k);
For(i, 1, n) read(val[i]);
For(i, 1, m){
read(u); read(v); read(w);
w++;
UV t1 = (UV){u, v}, t2 = (UV){v, u};
ms[t1] = ms[t2] = w;
lcts[w].link(u, v);
}
For(ca, 1, k){
read(op);
// printf("op = %d\n", op);
if(op == 0){
read(x); read(w);
val[x] = w;
For(i, 1, c) lcts[i].splay(x);
}else if(op == 1){
read(u); read(v); read(w);
w++;
UV tmp = (UV){u, v}, t2 = (UV){v, u};
if(!ms.count(tmp)){
printf("No such edge.\n");
continue;
}
int bef = ms[tmp];
if(bef == w){
printf("Success.\n");
continue;
}
if(lcts[w].du[u] >= 2 || lcts[w].du[v] >= 2){
printf("Error 1.\n");
continue;
}
if(lcts[w].find(u) == lcts[w].find(v)){
printf("Error 2.\n");
continue;
}
printf("Success.\n");
lcts[bef].cut(u, v); lcts[w].link(u, v);
ms[tmp] = ms[t2] = w;
}else{
read(w); read(u); read(v);
w++;
if(lcts[w].find(u) != lcts[w].find(v)){
printf("-1\n");
continue;
}
printf("%d\n", lcts[w].query(u, v));
}
}
return 0;
}