题目描述
样例
input:
6 6 3 3 1
1000007
1 1 1 2 2 3
1 6 1
1 2 5
2 3 4
3 6 3
3 4 6
5 6 2
0 2
5 6
9 11
output:
5
8
7
分析
可以先跑最小生成树,求出这个图中从xxx到达任意一个节点所需要的最大困难程度的最小值。
此时有一个很好的思路:
用一个t[i]t[i]t[i]表示种类iii妹子被半仙访问所需要的最少困难程度。最后算的时候枚举妹子的种类,然后判断一下t[i]t[i]t[i]与l,rl,rl,r的大小关系就可以快速加进答案里了。
问题是,怎么搞t[i]t[i]t[i]呢???很简单,只要dfsdfsdfs跑一次,记下从xxx到其他节点路上的最大值然后与原来记录的类型iii的t[i]t[i]t[i]比较一下记一下最小值就可以了。
代码
#include<bits/stdc++.h>
#define ll long long
#define inf 1<<30//注意1<<29小于1e9,调了半天
using namespace std;
const int MAXN=5e5+10;
struct node{
int to,w;
node(){}
node(int _to,int _w){
to=_to;w=_w;
}
};
vector<node> vec[MAXN];
struct edge{int u,v,w;}e[MAXN];
int fa[MAXN],c[MAXN],t[MAXN];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
bool cmp(edge a,edge b){return a.w<b.w;}
void add(int u,int v,int w){
vec[u].push_back(node(v,w));
vec[v].push_back(node(u,w));
}
void dfs(int x,int maxn,int f){
t[c[x]]=min(t[c[x]],maxn);//与原来的t[i]比较,c[i]是i妹子的种类
for(int i=0;i<vec[x].size();i++)
if(vec[x][i].to!=f)
dfs(vec[x][i].to,max(maxn,vec[x][i].w),x);
}
int main()
{
int n,m,q,x,opt,mod;ll l,r;
scanf("%d%d%d%d%d",&n,&m,&q,&x,&opt);
if(opt) scanf("%d",&mod);int lmt=0;
for(int i=1;i<=n;i++) scanf("%d",&c[i]),lmt=max(lmt,c[i]);
for(int i=1,u,v,w;i<=m;i++)
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=lmt;i++) t[i]=inf;
sort(e+1,e+1+m,cmp);
for(int i=1,u,v,w;i<=m;i++){
u=e[i].u;v=e[i].v;w=e[i].w;
if(find(u)!=find(v)) fa[fa[u]]=fa[v],add(u,v,w);//kruskal求最小生成树
}dfs(x,0,0);ll ans=0;
while(q--){
scanf("%lld%lld",&l,&r);
if(opt) l=(l^ans)%(ll)mod+1,r=(r^ans)%(ll)mod+1;//强制在线烦死了
if(l>r) swap(l,r);ans=0;
for(int i=1;i<=lmt;i++)
if(t[i]<=l) ans+=(ll)(r-l+1);
//如果所需的t[i]小于区间的下界,那么对于这个种类,无论忍受程度是(l,r)间的哪一个都是可以+1
//所以在ans中加r-l+1
else if(t[i]<=r) ans+=(ll)(r-t[i]+1);
//否则就只能加能加的部分
printf("%lld\n",ans);
}
}
END
- 注意inf的设置,一定一定要小心,尽量开ll。