##BZOJ 2594 [Wc2006]水管局长数据加强版
倒着看 删边就成了加边
加边时若在当前的树上成环 并且这条边的边权<环上最大边权 则删去环上边权最大的边 连上新加入的边
lct维护下这棵树
边权可以拆成点权来处理 例如u->v w 可以拆成 u->t t->v t的点权为w
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#define ls ch[o][0]
#define rs ch[o][1]
#define M 1000005
#define INF 1000000000
#define MAXN (100005+1000005)
#define N 100005
using namespace std;
int read()
{
int t=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){t=t*10+ch-'0';ch=getchar();}
return t*f;
}
int n,m,q;
int w[MAXN],mx[MAXN],ch[MAXN][2],fa[MAXN],s[MAXN];
bool rev[MAXN];
vector<int> ans;
bool is_root(int o)
{
return (ch[fa[o]][0]!=o)&&(ch[fa[o]][1]!=o);
}
void pushup(int o)
{
mx[o]=o;
if(ls&&w[mx[ls]]>w[mx[o]]) mx[o]=mx[ls];
if(rs&&w[mx[rs]]>w[mx[o]]) mx[o]=mx[rs];
}
void reverse(int o)
{
rev[o]^=1;
swap(ls,rs);
}
void pushdown(int o)
{
if(!rev[o]) return;
if(ls) reverse(ls);
if(rs) reverse(rs);
rev[o]=0;
}
void rotate(int o,int d)
{
int x=fa[o],y=fa[x],z=(ch[y][1]==x);
if(!is_root(x)) ch[y][z]=o;
ch[x][d^1]=ch[o][d],fa[ch[o][d]]=x;
ch[o][d]=x,fa[x]=o,fa[o]=y;
pushup(x),pushup(o),pushup(y);
}
int st[MAXN],top=0;
void splay(int o)
{
st[++top]=o;
for(int i=o;!is_root(i);i=fa[i])
st[++top]=fa[i];
while(top) pushdown(st[top--]);
while(!is_root(o))
{
int x=fa[o],y=fa[x],d1=ch[x][0]==o,d2=ch[y][0]==x;
if(is_root(x)) rotate(o,d1);
else
{
if(d1==d2) rotate(x,d1),rotate(o,d1);
else rotate(o,d1),rotate(o,d2);
}
}
}
void access(int o)
{
int t=0;
while(o)
{
splay(o),rs=t;
pushup(o),t=o;
o=fa[o];
}
}
void make_root(int o)
{
access(o),splay(o);
reverse(o);
}
void cut(int u,int v)
{
make_root(u);
access(v),splay(v);
ch[v][0]=fa[u]=0;
pushup(v);
}
void join(int u,int v)
{
make_root(u);
fa[u]=v;
}
int find(int o)
{
while(fa[o]) o=fa[o];
return o;
}
int query(int u,int v)
{
make_root(u),access(v),splay(v);
return mx[v];
}
struct edge
{
int u,v,t,tag;
bool del;
bool operator <(edge t)const
{
if(u==t.u)
return v<t.v;
return u<t.u;
}
}e[M];
struct op{int k,a,b,id;}p[MAXN];
bool cmp(edge a,edge b){return a.t<b.t;}
void mst()
{
int cnt=0;
sort(e+1,e+1+m,cmp);
for(int i=1;i<=n;i++)
w[i]=-INF,mx[i]=i;
for(int i=1;i<=m;i++)
w[e[i].tag]=e[i].t,mx[e[i].tag]=e[i].tag;
for(int i=1;i<=m;i++)
{
if(e[i].del) continue;
if(find(e[i].u)!=find(e[i].v))
{
cnt++;
join(e[i].u,e[i].tag);
join(e[i].v,e[i].tag);
if(cnt==n-1) break;
}
}
}
int main()
{
n=read(),m=read(),q=read();
for(int i=1;i<=m;i++)
{
e[i].u=read();
e[i].v=read();
e[i].t=read();
}
sort(e+1,e+1+m);
for(int i=1;i<=m;i++)
e[i].tag=n+i;
for(int i=1;i<=q;i++)
{
p[i].k=read();
p[i].a=read();
p[i].b=read();
if(p[i].k==2)
{
edge tmp; tmp.u=p[i].a,tmp.v=p[i].b;
int idx=lower_bound(e+1,e+1+m,tmp)-e;
e[idx].del=1,p[i].id=idx;
}
}
mst();
sort(e+1,e+1+m);
for(int i=q;i;i--)
{
int u=p[i].a,v=p[i].b;
if(p[i].k==1) ans.push_back(w[query(u,v)]);
else
{
if(find(u)!=find(v))
{
join(u,e[p[i].id].tag);
join(v,e[p[i].id].tag);
}
else
{
int t=query(u,v),id=p[i].id;
if(e[id].t>=w[t]) continue;
cut(e[t-n].u,t);
cut(e[t-n].v,t);
join(id+n,u);
join(id+n,v);
}
}
}
for(int i=ans.size()-1;i>=0;i--)
printf("%d\n",ans[i]);
return 0;
}
##BZOJ 3669 [Noi2014]魔法森林
按a排序后依次加边 维护最小生成树即可
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#define M 100000*2
#define INF 1000000000
#define MAXN 100000*2
#define N 100000*2
#define ls ch[o][0]
#define rs ch[o][1]
using namespace std;
int read()
{
int t=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){t=t*10+ch-'0';ch=getchar();}
return t*f;
}
int n,m,ans=INF;
int ch[MAXN][2],fa[MAXN],mx[MAXN],w[MAXN];
bool rev[MAXN];
struct edge
{
int u,v,a,b;
bool operator <(edge t)const{return a<t.a;}
}e[M];
bool is_root(int o)
{
return (ch[fa[o]][0]!=o)&&(ch[fa[o]][1]!=o);
}
void reverse(int o)
{
rev[o]^=1;
swap(ls,rs);
}
void pushdown(int o)
{
if(!rev[o]) return;
if(ls) reverse(ls);
if(rs) reverse(rs);
rev[o]=0;
}
void pushup(int o)
{
mx[o]=o;
if(ls&&w[mx[ls]]>w[mx[o]]) mx[o]=mx[ls];
if(rs&&w[mx[rs]]>w[mx[o]]) mx[o]=mx[rs];
}
void rotate(int o,int d)
{
int x=fa[o],y=fa[x],z=ch[y][1]==x;
if(!is_root(x)) ch[y][z]=o;
ch[x][d^1]=ch[o][d],fa[ch[o][d]]=x;
ch[o][d]=x,fa[x]=o,fa[o]=y;
pushup(x),pushup(o),pushup(y);
}
int st[MAXN],top=0;
void splay(int o)
{
st[++top]=o;
for(int i=o;!is_root(i);i=fa[i])
st[++top]=fa[i];
while(top) pushdown(st[top--]);
while(!is_root(o))
{
int x=fa[o],y=fa[x],d1=ch[x][0]==o,d2=ch[y][0]==x;
if(is_root(x)) rotate(o,d1);
else
{
if(d1==d2) rotate(x,d1),rotate(o,d2);
else rotate(o,d1),rotate(o,d2);
}
}
}
void access(int o)
{
int t=0;
while(o)
{
splay(o),rs=t,pushup(o);
t=o,o=fa[o];
}
}
void make_root(int o){access(o),splay(o),reverse(o);}
void join(int u,int v){make_root(u),fa[u]=v;}
void cut(int u,int v)
{
make_root(u),access(v),splay(v);
ch[v][0]=fa[u]=0,pushup(v);
}
int find(int o)
{
while(fa[o]) o=fa[o];
return o;
}
int query(int u,int v)
{
make_root(u),access(v),splay(v);
return mx[v];
}
int main()
{
n=read(),m=read();
for(int i=1;i<=m;i++)
{
e[i].u=read();
e[i].v=read();
e[i].a=read();
e[i].b=read();
}
sort(e+1,e+1+m);
for(int i=1;i<=n;i++) mx[i]=i,w[i]=0;
for(int i=1;i<=m;i++) mx[i+n]=i+m,w[i+n]=e[i].b;
for(int i=1;i<=m;i++)
{
if(find(e[i].u)!=find(e[i].v))
{
join(e[i].u,i+n);
join(e[i].v,i+n);
}
else
{
int t=query(e[i].u,e[i].v);
if(e[i].b>=w[t]) continue;
cut(e[t-n].u,t);
cut(e[t-n].v,t);
join(e[i].u,i+n);
join(e[i].v,i+n);
}
if(find(1)==find(n)) ans=min(ans,e[i].a+w[query(1,n)]);
}
printf("%d\n",ans==INF?-1:ans);
return 0;
}
##BZOJ 3514 Codechef MARCH14 GERALD07加强版
hzwer Orz
NTR大法好
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#define M 200005*2
#define INF 1000000000
#define MAXN (200005*50)
#define N 200005
using namespace std;
int read()
{
int t=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){t=t*10+ch-'0';ch=getchar();}
return t*f;
}
#define ls ch[o][0]
#define rs ch[o][1]
int fa[M],ch[M][2],mn[M],w[M];
bool rev[M];
bool is_root(int o){return (ch[fa[o]][0]!=o)&&(ch[fa[o]][1]!=o);}
void reverse(int o){rev[o]^=1,swap(ls,rs);}
void pushdown(int o)
{
if(!rev[o]) return;
if(ls) reverse(ls);
if(rs) reverse(rs);
rev[o]=0;
}
void pushup(int o)
{
mn[o]=o;
if(ls&&w[mn[ls]]<w[mn[o]]) mn[o]=mn[ls];
if(rs&&w[mn[rs]]<w[mn[o]]) mn[o]=mn[rs];
}
void rotate(int o,int d)
{
int x=fa[o],y=fa[x],z=ch[y][1]==x;
if(!is_root(x)) ch[y][z]=o;
ch[x][d^1]=ch[o][d],fa[ch[o][d]]=x;
ch[o][d]=x,fa[x]=o,fa[o]=y;
pushup(x),pushup(o),pushup(y);
}
int st[M],top=0;
void splay(int o)
{
st[++top]=o;
for(int i=o;!is_root(i);i=fa[i])
st[++top]=fa[i];
while(top) pushdown(st[top--]);
while(!is_root(o))
{
int x=fa[o],y=fa[x],d1=ch[x][0]==o,d2=ch[y][0]==x;
if(is_root(x)) rotate(o,d1);
else
{
if(d1==d2) rotate(x,d1),rotate(o,d1);
else rotate(o,d1),rotate(o,d2);
}
}
}
void access(int o)
{
int t=0;
while(o)
{
splay(o),rs=t;
pushup(o);
t=o,o=fa[o];
}
}
void make_root(int o){access(o),splay(o),reverse(o);}
void join(int u,int v){make_root(u),fa[u]=v;}
void cut(int u,int v)
{
make_root(u),access(v),splay(v);
fa[u]=ch[v][0]=0,pushup(v);
}
int find(int o)
{
while(fa[o])o=fa[o];
return o;
}
int query(int u,int v)
{
make_root(u),access(v),splay(v);
return mn[v];
}
#define mid ((l+r)>>1)
#undef ls
#undef rs
int cnt=0;
int root[MAXN],ls[MAXN],rs[MAXN],s[MAXN];
void update(int pre,int &rt,int l,int r,int v)
{
rt=++cnt,s[rt]=s[pre]+1;
ls[rt]=ls[pre],rs[rt]=rs[pre];
if(l==r) return;
if(v<=mid) update(ls[pre],ls[rt],l,mid,v);
else update(rs[pre],rs[rt],mid+1,r,v);
}
int ask(int rt,int l,int r,int nl,int nr)
{
if(l==nl&&r==nr) return s[rt];
if(nr<=mid) return ask(ls[rt],l,mid,nl,nr);
else if(nl>mid) return ask(rs[rt],mid+1,r,nl,nr);
else return ask(ls[rt],l,mid,nl,mid)+ask(rs[rt],mid+1,r,mid+1,nr);
}
int n,m,k,type,ntr[N];
struct edge{int u,v;}e[N];
int main()
{
n=read(),m=read(),k=read(),type=read();
w[0]=INF;
for(int i=1;i<=m;i++)
{
e[i].u=read();
e[i].v=read();
}
for(int i=1;i<=n;i++) mn[i]=i,w[i]=INF;
for(int i=1;i<=m;i++) w[n+i]=i,mn[n+i]=n+i;
for(int i=1;i<=m;i++)
{
if(e[i].u==e[i].v){ntr[i]=i;continue;}
if(find(e[i].u)==find(e[i].v))
{
int t=query(e[i].u,e[i].v);
ntr[i]=t-n;
cut(t,e[t-n].u);
cut(t,e[t-n].v);
}
join(e[i].u,i+n);
join(e[i].v,i+n);
}
for(int i=1;i<=m;i++)
update(root[i-1],root[i],0,m,ntr[i]);
for(int i=1,ans=0;i<=k;i++)
{
int l=read(),r=read();
if(type) l^=ans,r^=ans;
int t=ask(root[r],0,m,0,l-1)-ask(root[l-1],0,m,0,l-1);
printf("%d\n",ans=n-t);
}
return 0;
}