5216: [Lydsy2017省队十连测]公路建设
用线段树维护每段区间最优解,每个节点记录所用边;
因为(n)只有(100),所以向上合并时暴力归并+并查集即可;
AC GET☆DAZE
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define N 139
#define mod 20070831
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
struct Seg_Tree
{
int l,r,ans[102];
}tree[100039<<2];
struct edge
{
int u,v,w;
}net[100039];
int n,m,q,fa[N],fu,fv,use,ans[N][N];
int find(int k)
{
return fa[k]==k ? k : fa[k]=find(fa[k]);
}
void pull_up(int res[],int i[],int j[])
{
int now=0,li=1,lj=1;
for(int a=1;a<=n;a++) fa[a]=a;
while(now<n && (i[li] || j[lj]))
{
while(now<n && i[li] && net[i[li]].w<=net[j[lj]].w)
{
fu=find(net[i[li]].u),fv=find(net[i[li]].v);
if(fu!=fv) fa[fu]=fv,res[++now]=i[li];
li++;
}
while(now<n && j[lj] && net[i[li]].w>=net[j[lj]].w)
{
fu=find(net[j[lj]].u),fv=find(net[j[lj]].v);
if(fu!=fv) fa[fu]=fv,res[++now]=j[lj];
lj++;
}
}
while(now<n && res[now]) res[++now]=0;
}
void build(int k,int l,int r)
{
tree[k].l=l,tree[k].r=r;
if(l==r)
{
tree[k].ans[1]=r;
return;
}
int mid=l+r>>1;
build(k<<1,l,mid),build(k<<1|1,mid+1,r);
pull_up(tree[k].ans,tree[k<<1].ans,tree[k<<1|1].ans);
}
void query(int k,int l,int r,int now)
{
if(l<=tree[k].l && tree[k].r<=r)
{
for(int a=1;a<n;a++) ans[now][a]=tree[k].ans[a];
return;
}
int mid=tree[k].l+tree[k].r>>1,ls=0,rs=0;
if(mid>=r) query(k<<1,l,r,ls=++use);
else if(mid<l) query(k<<1|1,l,r,rs=++use);
else query(k<<1,l,mid,ls=++use),query(k<<1|1,mid+1,r,rs=++use);
if(ls && !rs) for(int a=1;a<n;a++) ans[now][a]=ans[ls][a];
if(!ls && rs) for(int a=1;a<n;a++) ans[now][a]=ans[rs][a];
if(ls && rs) pull_up(ans[now],ans[ls],ans[rs]);
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
for(int a=1;a<=m;a++)
{
scanf("%d%d%d",&net[a].u,&net[a].v,&net[a].w);
}
net[0].w=inf;
build(1,1,m);
for(int a=1,b,c,d=0;a<=q;a++,d=0)
{
scanf("%d%d",&b,&c);
query(1,b,c,use=1);
for(int e=1;ans[1][e];e++)
{
d+=net[ans[1][e]].w;
}
printf("%d
",d);
}
return 0;
}