红蓝图 kruskal重构树+dfs序+线段树合并
题解:
如果不会kruskal重构树,建议先写 D. Graph and Queries 并查集+线段树+kruskal重构树
- 首先对查询按照 t 从大到小排序,然后按照权值从大到小建一棵kruskal重构树,然后dfs求出每一个节点的dfs序,顺便求出每一个询问节点的子树节点。
- 对于每一个节点都建一棵动态开点的线段树,然后对查询按照 t 从小到大排序,边建线段树边输出询问。
#include <bits/stdc++.h>
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register int x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
const int maxn = 1e6+10;
int a[maxn],b[maxn],c[maxn];
struct node{
int x,t,id;
node(int x=0,int t=0,int id=0):x(x),t(t),id(id){}
}e[maxn];
bool cmp(node a,node b){
return a.t<b.t;
}
int head[maxn],to[maxn<<1],nxt[maxn<<1],cnt;
void add(int u,int v){
// printf("u = %d v = %d
", u,v);
++cnt,to[cnt]=v,nxt[cnt]=head[u],head[u]=cnt;
++cnt,to[cnt]=u,nxt[cnt]=head[v],head[v]=cnt;
}
int f[maxn],now;
int find(int x){
return f[x]==x?x:f[x]=find(f[x]);
}
void unite(int x,int y){
x = find(x),y = find(y);
if(x == y) return ;
++now,add(x,now),add(y,now);
f[now] = f[x] = f[y] = now;
}
int subTree[maxn],el[maxn],er[maxn],tot;
void dfs(int u,int pre){
el[u] = ++tot;
for(int i=head[u];i;i=nxt[i]){
int v = to[i];
if(v == pre) continue;
dfs(v,u);
}
er[u] = tot;
}
int root[maxn],sum[maxn<<2],sz,lc[maxn<<2],rc[maxn<<2];
void push_up(int id){
sum[id] = sum[lc[id]] + sum[rc[id]];
}
void update(int &id,int l,int r,int pos){
if(!id) id = ++sz;
if(l==r){
sum[id] = 1;
return ;
}
int mid = (l+r)>>1;
if(pos<=mid) update(lc[id],l,mid,pos);
if(pos>mid) update(rc[id],mid+1,r,pos);
push_up(id);
}
int merge(int x,int y,int l,int r){
if(!x) return y;
if(!y) return x;
if(l==r){
sum[x] += sum[y];
return x;
}
int mid = (l+r)>>1;
lc[x] = merge(lc[x],lc[y],l,mid);
rc[x] = merge(rc[x],rc[y],mid+1,r);
push_up(x);
return x;
}
int ans[maxn];
int query(int id,int l,int r,int x,int y){
// printf("query:id = %d l = %d r = %d x =%d y = %d
", id,l,r,x,y);
if(!id) return 0;
if(x<=l&&y>=r) return sum[id];
int mid = (l+r)>>1,ans = 0;
if(x<=mid) ans += query(lc[id],l,mid,x,y);
if(y>mid) ans += query(rc[id],mid+1,r,x,y);
return ans;
}
void debug(int id,int l,int r){
if(!id) return ;
printf("id = %d l = %d r = %d sum=%d
", id,l,r,sum[id]);
if(l==r) return;
int mid = (l+r)>>1;
debug(lc[id],l,mid);
debug(rc[id],mid+1,r);
}
int main(){
int n = read(),m = read(),q = read();
now = n,cnt = 0,tot = 0,sz = 0;
for(int i=1;i<=n+m;i++) f[i] = i;
for(int i=1;i<=m;i++){
a[i] = read() + 1,b[i] = read() + 1,c[i] = read();
}
for(int i=1;i<=q;i++){
int x = read() + 1,t = read();
e[i] = node(x,t,i);
}
int cur = m;
sort(e+1,e+1+q,cmp);
for(int i=q;i>=1;i--){
while(cur>=1&&cur>=e[i].t){
if(c[cur]) unite(a[cur],b[cur]);
cur--;
}
subTree[i] = find(e[i].x);
}
for(int i=1;i<=n+m;i++){
find(i);
if(f[i]==i) dfs(i,0);
}
for(int i=1;i<=n;i++) update(root[i],1,now,el[i]);
cur = 1;
for(int i=1;i<=n;i++) f[i] = i;
for(int i=1;i<=q;i++){
while(cur<=m&&cur<=e[i].t){
if(!c[cur]) {
int x = find(a[cur]),y = find(b[cur]);
if(x!=y){
root[x]=root[y]=merge(root[x],root[y],1,now);
f[x] = y;
}
}
cur++;
}
int pos = root[find(e[i].x)];
ans[e[i].id] = query(pos,1,now,el[subTree[i]],er[subTree[i]]);
}
for(register int i=1;i<=q;++i) write(ans[i]),puts("");
return 0;
}