http://47.92.197.167:5283/contest/408/problem/4
两个可以推的经典套路:
- 我们可以对所有点建序树,然后取前 k k k 大。而取前 k k k 大可以通过以直径端点为根长剖来贪心
- 直径具有合并性(不仅是连通块,而且是点集)。同理,前 k k k 大的点也具有合并性。
想到这里,我们就已经知道对于相应点集如何求答案。同时知道如何对两个点集进行合并,我们就可以直接上线段树了。
然而可以更优化。我们可以考虑分块。以 k k k 分块。查询连续块我们可以用ST表预处理。散块我们和连续块的一起跑一遍虚树。
cpp
// 6k
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar(); while(ch<'0'||
ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
//mt19937 rand(time(0));
//mt19937_64 rand(time(0));
//srand(time(0));
#define N 200010
//#define M
//#define mo
int n, m, i, j, k, T, lstans;
inline void decode(int &l, int &r, int &k, int lstans, int testop) {
lstans %= 19260817;
if(testop) {
l ^= lstans; l = (l % n + n) % n + 1;
r ^= lstans; r = (r % n + n) % n + 1;
if(l > r) std :: swap(l, r);
k ^= lstans;
k = (k % std :: min(r - l + 1, 100ll)) + 1;
}
}
struct node {
int y, z;
};
vector<node>G[N], Xu[N];
int dep[N], dfn[N], f[N][22], tot;
int h[N], Log2[N], id, op, K, p[N];
int l, r, L[N], R[N], s[N], q, li, ri;
int lca(int x, int y) {
if(x==y) return x;
// printf("1(%lld %lld) %lld %lld\n", x, y, dep[x], dep[y]);
if(dep[x]<dep[y]) swap(x, y);
// printf("1(%lld %lld) %lld %lld\n", x, y, dep[x], dep[y]);
for(int k=20; k>=0; --k)
if(dep[f[x][k]]>=dep[y]) x=f[x][k];
// printf("2(%lld %lld) %lld %lld\n", x, y, dep[x], dep[y]);
if(x==y) return x;
for(int k=20; k>=0; --k)
if(f[x][k]!=f[y][k]) x=f[x][k], y=f[y][k];
return f[x][0];
}
void dfs(int x, int fa) {
dfn[x]=++tot; dep[x]=dep[fa]+1;
for(auto t : G[x]) {
int y=t.y, z=t.z;
if(y==fa) continue;
// printf("%d -> %d\n", x, y);
h[y]=h[x]+z; f[y][0]=x;
dfs(y, x);
}
}
vector<int>F;
int mxh[N], son[N], w[N], H[N];
int summmm;
map<int, int>mp;
struct Xu_tree {
vector<int>s, ans;
int x, y, z, i, n, rt1, rt2;
void dfs_zhi(int x, int fa, int &rt) {
if(H[x]>H[rt]) rt=x;
for(auto t : Xu[x]) {
int y=t.y, z=t.z;
if(y==fa) continue;
H[y]=H[x]+z;
dfs_zhi(y, x, rt);
}
}
void dfs1(int x, int fa) {
mxh[x]=son[x]=0;
for(auto t : Xu[x]) {
int y=t.y, z=t.z;
if(y==fa) continue;
dfs1(y, x); mxh[y]+=z;
// printf("%lld : %lld\n", )
if(mxh[y]>mxh[son[x]]) son[x]=y;
}
mxh[x]=mxh[son[x]];
// printf("mxh[%lld]=%lld\n", x, mxh[x]);
// mxh[x]=mxh[son[x]];
}
void dfs2(int x, int fa, int S) {
w[x]=S;
// printf("w[%lld]=%lld\n", x, w[x]);
for(auto t : Xu[x]) {
int y=t.y, z=t.z;
if(y==fa) continue;
// printf("%lld -> %lld (%lld) %lld\n", x, y, son[x], z);
w[x]=0;
if(y==son[x]) dfs2(y, x, S+z);
else dfs2(y, x, z);
}
}
void build() {
F.clear(); mp.clear();
// printf("%lld\n", s.size());
// summmm+=s.size();
sort(s.begin(), s.end(), [] (int x, int y) { return dfn[x]<dfn[y]; });
n=unique(s.begin(), s.end())-s.begin();
s.resize(n);
// for(auto i : s) printf("%lld ", i); printf("\n");
n=s.size(); F.pb(s[0]);
for(int i=1; i<n; ++i) {
x=s[i-1]; y=s[i]; z=lca(x, y); mp[x]=mp[y]=1;
// printf("lca(%d, %d)=%d\n", x, y, z);
F.pb(y); F.pb(z);
}
// printf("%lld\n", F.size());
sort(F.begin(), F.end(), [] (int x, int y) { return dfn[x]<dfn[y]; });
n=unique(F.begin(), F.end())-F.begin();
F.resize(n);
// summmm+=F.size();
for(auto i : F) Xu[i].clear();
n=F.size();
for(int i=1; i<n; ++i) {
x=F[i-1]; y=F[i]; z=lca(x, y);
// printf("%d -> %d\n", y, z);
Xu[z].pb({y, h[y]-h[z]});
Xu[y].pb({z, h[y]-h[z]});
}
H[F[0]]=rt1=0; dfs_zhi(F[0], 0, rt1);
// H[rt1]=0; dfs(rt1, 0, rt2);
dfs1(rt1, 0);
dfs2(rt1, 0, 0);
sort(F.begin(), F.end(), [] (int x, int y) { return w[x]>w[y]; }) ;
// for(auto i : F) printf("%lld ", i); printf("\n");
// for(auto i : F) printf("%lld ", w[i]); printf("\n");
s.clear(); ans.clear();
for(int i=0; i<n; ++i) {
if(!mp[F[i]]) continue;
ans.pb(w[F[i]]); s.pb(F[i]);
if(ans.size()>K) break;
}
s.pb(rt1);
// printf("rt1 : %lld\n", rt1);
// for(auto i : ans) printf("%lld ", i); printf("\n");
// for(auto i : s) printf("%lld ", i); printf("\n");
}
void merge(Xu_tree A) {
// s.clear();
for(auto i : A.s) s.pb(i);
}
int que(int x) {
int Ans=0; n=ans.size();
for(i=0; i<min(x, n); ++i)
Ans+=ans[i];
return Ans;
}
}dp[N][12], As;
void Merge(int l, int r) {
int k = Log2[r-l+1];
// printf("[%lld %lld] %lld\n", l, r, k);
As.merge(dp[l][k]);
As.merge(dp[r-(1<<k)+1][k]);
}
signed main()
{
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
freopen("nomenclature.in", "r", stdin);
freopen("nomenclature.out", "w", stdout);
// T=read();
// while(T--) {
//
// }
id=read(); op=read(); n=read(); K=300;
for(i=1; i<n; ++i) {
int u, v, w;
u=read(); v=read(); w=read();
G[u].pb({v, w}); G[v].pb({u, w});
}
dfs(1, 0);
for(k=1; k<=20; ++k)
for(i=1; i<=n; ++i)
f[i][k]=f[f[i][k-1]][k-1];
for(i=1; i<=n; ++i) p[i]=read();
for(l=i=1; l<=n; l=r+1, ++i) {
r=min(n, l+K-1); L[i]=l; R[i]=r;
for(j=l; j<=r; ++j) s[j]=i, dp[i][0].s.pb(p[j]);
dp[i][0].build();
}
// int cntt=0;
m=n/K+1;
// printf("%lld\n", m);
for(i=2; i<=n; ++i) Log2[i]=Log2[i>>1]+1;
for(k=1; k<=22; ++k)
for(i=1; i+(1<<k)-1<=m; ++i){
// ++cntt;
dp[i][k].merge(dp[i][k-1]);
dp[i][k].merge(dp[i+(1<<k-1)][k-1]);
dp[i][k].build();
}
// printf("%lld %lld\n", cntt, summmm);
printf("-------\n");
//
q=read();
while(q--) {
l=read(); r=read(); k=read();
decode(l, r, k, lstans, op);
// printf("[%lld %lld] %lld\n", l, r, k);
if(k==1) { printf("0\n"); lstans=0; continue; }
li=s[l]; ri=s[r]; As.s.clear(); As.ans.clear();
for(i=l; s[i]==s[l] && i<=r; ++i) As.s.pb(p[i]);
for(i=r; s[i]==s[r] && i>=l && li!=ri; --i) As.s.pb(p[i]);
if(li+1<=ri-1) Merge(li+1, ri-1);
As.build();
lstans=As.que(k-1);
// printf("# ");
printf("%lld\n", lstans);
}
return 0;
}