标签:ons 长度 启发式 pre name getch 线段 and include
实为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;
}
标签:ons 长度 启发式 pre name getch 线段 and include
原文地址:https://www.cnblogs.com/cooper233/p/11792835.html