实为1027练习题C-遥色点对题解
给出一张由编号1到n的n个点和m条边构成的无向图。每条边都有一定的长度。 定义,一条路径的“代价”:该路径上最长一条边的长度。 定义,点x到点y的“点距”:点x到点y的最小代价。 图中每个点都被涂上了颜色,第i号点的颜色编号为Ci。 满足x<y 且|Cx-Cy|>=K 的任意一对点(x,y)都被称为“遥色点对”
现在需要你求出图中所有遥色点对的点距之和。
动态开点线段树启发式合并
#include<stdio.h> #include<bits/stdc++.h> #define f(a,b,c) for(register int a=(b);a<=(c);++a) #define ff(a,b,c) for(register int a=(b);a>=(c);--a) #define ll long long #define max(a,b) ((a)>(b)?(a):(b)) //#define int long long char pbuf[1<<20],*pp1=pbuf; inline void push(char c){*pp1=c;pp1=(pp1-pbuf==(1<<20)-1)?(fwrite(pbuf,1,1<<20,stdout),pbuf):(pp1+1);} //#define pc push #define pc putchar #define pe pc('\n') #define ps pc(' ') #define wer rd() char *p1,*p2,buf[1<<20]; #define GC (p1==p2&&(p1=buf,p2=buf+fread(buf,1,1<<20,stdin),p1==p2)?0:(*(p1++))) //#define GC getchar() using namespace std; inline ll wer{ ll ans;char t,k; while(((t=GC)!='-')&&(t>'9'||t<'0')); k=(t=='-'); ans=k?0:(t-'0'); while((t=GC)>='0'&&t<='9')ans=ans*10+t-'0'; return k?-ans:ans; } inline void wt(ll k) { if(k<0)pc('-'),wt(-k); else { if(k<10)pc('0'+k); else wt(k/10),pc('0'+k%10); } return; } const int N=2e5+5; int n,m,K; int ck[N<<5],k[N<<5],ls[N<<5],rs[N<<5],rt[N],tot; int build(int l,int r,int x) { if(r<x||x<l)return 0; int now=ck[tot--]; if(l==r){k[now]=1;return now;} int mid=l+r>>1; ls[now]=build(l,mid,x); rs[now]=build(mid+1,r,x); k[now]=k[ls[now]]+k[rs[now]]; return now; } int merge(int x,int y,int l,int r)//merge y to x and delete y { if(y==0)return x; if(x==0)x=ck[tot--],k[x]=0,ls[x]=0,rs[x]=0; if(l==r){ k[x]+=k[y]; k[y]=0; ck[++tot]=y; return x; } int mid=l+r>>1; ls[x]=merge(ls[x],ls[y],l,mid); rs[x]=merge(rs[x],rs[y],mid+1,r); k[x]=k[ls[x]]+k[rs[x]]; k[y]=0; ck[++tot]=y; return x; } int sum(int now,int l,int r,int x,int y) { if(!now||y<x)return 0; if(r<x||y<l)return 0; if(x<=l&&r<=y)return k[now]; int mid=l+r>>1; return sum(ls[now],l,mid,x,y)+sum(rs[now],mid+1,r,x,y); } #define maxn 1000000000 int ans=0; void countans(int now,int l,int r,int to) { if(!now)return; if(l==r) { if(K==0)ans+=k[now]*k[to]; else ans+=k[now]*(sum(to,1,maxn,1,l-K) +sum(to,1,maxn,l+K,maxn)); return; } int mid=l+r>>1; countans(ls[now],l,mid,to); countans(rs[now],mid+1,r,to); return; } void get(int now,int l,int r) { if(!now)return; if(l==r)wt(l),ps; else get(ls[now],l,(l+r>>1)),get(rs[now],(l+r>>1)+1,r); } vector<pair<int,pair<int,int> > >v; int c[N]; int f[N]; int getf(int x){return f[x]==x?x:(f[x]=getf(f[x]));} main() { n=wer,m=wer,K=wer; f(i,1,n<<5|1)ck[++tot]=i; f(i,1,n)c[i]=wer,f[i]=i,rt[i]=build(1,maxn,c[i]); // f(i,1,n)get(rt[i],1,maxn),pe; // cout<<"sdjadsff\n"; f(i,1,m) { int a=wer,b=wer,c=wer; v.push_back({c,{a,b}}); } sort(v.begin(),v.end()); if(v[0].first>v[v.size()-1].first)reverse(v.begin(),v.end()); int Ans=0; f(i,0,m-1) { int a=getf(v[i].second.first); int b=getf(v[i].second.second); if(a==b)continue; if(k[rt[a]]<k[rt[b]])swap(a,b); f[b]=a; // cout<<"now merge "<<a<<" to "<<b<<endl; // cout<<"sizeof "<<a<<":"<<k[rt[a]]<<"\n"; // cout<<"sizeof "<<b<<":"<<k[rt[b]]<<"\n"; // cout<<"what in "<<a<<":\n";get(rt[a],1,maxn);pe; // cout<<"what in "<<b<<":\n";get(rt[b],1,maxn);pe; ans=0; countans(rt[b],1,maxn,rt[a]); rt[a]=merge(rt[a],rt[b],1,maxn); // cout<<"now check tree "<<a<<"\n"; // get(rt[a],1,maxn);pe; Ans+=ans*v[i].first; } // wt(k[rt[getf(2)]]),pe; wt(Ans); fwrite(pbuf,1,pp1-pbuf,stdout); return 0; }