Statement

Solution
- 题目其实是求[l,r][l,r][l,r]内颜色数之和
- 我们看到ci≤600c_i \leq600ci≤600
- 快乐~
- 于是考虑每一种颜色,可以做到6∗1076*10^76∗107时复,约等于O(nn)O(n\sqrt n)O(nn)
- 先用KruskalKruskalKruskal跑出MSTMSTMST
- 然后记录到达每一种颜色路径上最大边权(#困难接受程度)
- 那么就可以算r−max(l,ti)+1r-\max(l,t_i)+1r−max(l,ti)+1次答案
- 代码很好写
#include <bits/stdc++.h>
#define ll long long
const int N=5e5+10;
using namespace std;
int n,m,q,X,C,op,h[N],tot,f[N],c[N],M;
int t[N];
struct rd{int u,v,w;}s[N<<1];
struct Edge{int v,nxt,w;}e[N<<1];
void add(int u,int v,int w)
{e[++tot].v=v,e[tot].nxt=h[u],e[tot].w=w,h[u]=tot;}
bool cmp(rd a,rd b){return a.w<b.w;}
int sf(int x){return x==f[x]?x:f[x]=sf(f[x]);}
void dfs(int x,int fx,int mn)
{
t[c[x]]=min(t[c[x]],mn);
for(int i=h[x];i;i=e[i].nxt)
{
int v=e[i].v;
if(v==fx) continue;
dfs(v,x,max(mn,e[i].w));
}
}
int main()
{
scanf("%d%d%d%d%d",&n,&m,&q,&X,&op);
if(op) scanf("%d",&M);
for(int i=1;i<=n;i++) scanf("%d",c+i),C=c[i]>C?c[i]:C,f[i]=i;
for(int i=1;i<=C;i++) t[i]=1<<30;
for(int i=1;i<=m;i++) scanf("%d%d%d",&s[i].u,&s[i].v,&s[i].w);
sort(s+1,s+m+1,cmp);
for(int i=1;i<=m;i++)
{
int x=s[i].u,y=s[i].v,z=s[i].w;
if(sf(x)^sf(y)) f[f[x]]=f[y],add(x,y,z),add(y,x,z);
}
dfs(X,0,0);
ll ans=0;
for(int i=1,l,r;i<=q;i++)
{
scanf("%d%d",&l,&r);
if(op) l=(l^ans)%M+1,r=(r^ans)%M+1;
if(l>r) l^=r^=l^=r;
ll tmp=0;
for(int i=1;i<=C;i++)
if(t[i]<=r) tmp+=1ll*(r-max(l,t[i])+1);
printf("%lld\n",ans=tmp);
}
}
Postscript
- 考场上没看懂题面
- 其实正解应该是O(NlogQ)O(NlogQ)O(NlogQ)的,求出每个点到x的最长的边的长度并保存,离散化,最后每次O(logQ)O(logQ)O(logQ)二分查询
- 可惜我太蒻了不会写,欢迎大佬在评论区指出!