Codeforces Round #625题解

DIV2A

只有第一个人独有的才对他有实际意义,其它的分数均视作1即可。

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<bitset>
#include<math.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
const int N=100000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u];i;i=sq[i].nxt)
#define fir first
#define sec second
#define mp make_pair
#define pb push_back
#define maxd 998244353
#define eps 1e-8
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*10+(ch-'0');ch=getchar();}
    return x*f;
}

namespace My_Math{
	#define N 100000

	int fac[N+100],invfac[N+100];

	int add(int x,int y) {return x+y>=maxd?x+y-maxd:x+y;}
	int dec(int x,int y) {return x<y?x-y+maxd:x-y;}
	int mul(int x,int y) {return 1ll*x*y%maxd;}
	ll qpow(ll x,int y)
	{
		ll ans=1;
		while (y)
		{
			if (y&1) ans=mul(ans,x);
			x=mul(x,x);y>>=1;
		}
		return ans;
	}
	int inv(int x) {return qpow(x,maxd-2);}

	int C(int n,int m)
	{
		if ((n<m) || (n<0) || (m<0)) return 0;
		return mul(mul(fac[n],invfac[m]),invfac[n-m]);
	}

	int math_init()
	{
		fac[0]=invfac[0]=1;
		rep(i,1,N) fac[i]=mul(fac[i-1],i);
		invfac[N]=inv(fac[N]);
		per(i,N-1,1) invfac[i]=mul(invfac[i+1],i+1);
	}
	#undef N
}
using namespace My_Math;
int n,a[1010],b[1010],c[1010],p[1010];

int main()
{
	n=read();
	rep(i,1,n) a[i]=read();
	rep(i,1,n) b[i]=read();
	int ok=0;
	rep(i,1,n) 
	{
		if (a[i]) c[i]+=1;
		if (b[i]) c[i]+=2;
		if (c[i]==1) ok=1;
	}
	if (!ok) {puts("-1");return 0;}
	int rst=0,cnt=0;
	rep(i,1,n)
	{
		if (c[i]>=2) p[i]=1;
		if (c[i]==2) rst+=p[i];
		if (c[i]==1) cnt++;
	}
	int ave=rst/cnt;ave++;
	rep(i,1,n) if (c[i]==1) p[i]=ave;
	cout << ave << endl;
	return 0;
}

DIV2B/DIV1A

合法序列的条件移项后得到\(c_i+b_{c_i}=c_{i+1}+b_{c_{i+1}}\),开个桶维护每个\(i+b_i\)最大的\(i\)即可。

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<bitset>
#include<math.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
const int N=100000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u];i;i=sq[i].nxt)
#define fir first
#define sec second
#define mp make_pair
#define pb push_back
#define maxd 998244353
#define eps 1e-8
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*10+(ch-'0');ch=getchar();}
    return x*f;
}

namespace My_Math{
	#define N 100000

	int fac[N+100],invfac[N+100];

	int add(int x,int y) {return x+y>=maxd?x+y-maxd:x+y;}
	int dec(int x,int y) {return x<y?x-y+maxd:x-y;}
	int mul(int x,int y) {return 1ll*x*y%maxd;}
	ll qpow(ll x,int y)
	{
		ll ans=1;
		while (y)
		{
			if (y&1) ans=mul(ans,x);
			x=mul(x,x);y>>=1;
		}
		return ans;
	}
	int inv(int x) {return qpow(x,maxd-2);}

	int C(int n,int m)
	{
		if ((n<m) || (n<0) || (m<0)) return 0;
		return mul(mul(fac[n],invfac[m]),invfac[n-m]);
	}

	int math_init()
	{
		fac[0]=invfac[0]=1;
		rep(i,1,N) fac[i]=mul(fac[i-1],i);
		invfac[N]=inv(fac[N]);
		per(i,N-1,1) invfac[i]=mul(invfac[i+1],i+1);
	}
	#undef N
}
using namespace My_Math;

const int bas=1000000;
int n,a[bas*4],b[bas*4];
ll f[600600];

int main()
{
	n=read();
	rep(i,1,n) a[i]=read();
	rep(i,1,n)
	{
		int now=i-a[i]+bas;
		f[i]=f[b[now]]+a[i];
		b[now]=i;
	}
	ll ans=0;
	rep(i,1,n) ans=max(ans,f[i]);
	cout << ans;
	return 0;
}

DIV2C

考虑一下当前可删的字典序最大字符,与它相邻的两个字符肯定不会因为它才能被删。于是每次删最大的字符的贪心是正确的。

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<bitset>
#include<math.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
const int N=100000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u];i;i=sq[i].nxt)
#define fir first
#define sec second
#define mp make_pair
#define pb push_back
#define maxd 998244353
#define eps 1e-8
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*10+(ch-'0');ch=getchar();}
    return x*f;
}

namespace My_Math{
	#define N 100000

	int fac[N+100],invfac[N+100];

	int add(int x,int y) {return x+y>=maxd?x+y-maxd:x+y;}
	int dec(int x,int y) {return x<y?x-y+maxd:x-y;}
	int mul(int x,int y) {return 1ll*x*y%maxd;}
	ll qpow(ll x,int y)
	{
		ll ans=1;
		while (y)
		{
			if (y&1) ans=mul(ans,x);
			x=mul(x,x);y>>=1;
		}
		return ans;
	}
	int inv(int x) {return qpow(x,maxd-2);}

	int C(int n,int m)
	{
		if ((n<m) || (n<0) || (m<0)) return 0;
		return mul(mul(fac[n],invfac[m]),invfac[n-m]);
	}

	int math_init()
	{
		fac[0]=invfac[0]=1;
		rep(i,1,N) fac[i]=mul(fac[i-1],i);
		invfac[N]=inv(fac[N]);
		per(i,N-1,1) invfac[i]=mul(invfac[i+1],i+1);
	}
	#undef N
}
using namespace My_Math;

int n;
char s[120];

int main()
{
	n=read();
	scanf("%s",s+1);
	int ans=0;
	while (1)
	{
		int p=0;
		rep(i,1,n)
		{
			if ((s[i]==s[i-1]+1) || (s[i]==s[i+1]+1))
			{
				if (!p) p=i;
				else if (s[p]<s[i]) p=i;
			}
		}
		if (!p) break;ans++;
		rep(i,p+1,n) s[i-1]=s[i];
		s[n]=' ';n--;
	}
	cout << ans;
	return 0;
}

DIV2D/DIV1B

建返图之后建以\(p_k\)为源的最短路图,接下来对每个\(p_i\)分类讨论。

  • \(p_i\)无法到达\(p_{i+1}\),那么这一步一定会带来一次\(\rm{rebuild}\).

  • \(p_i\)能到达多个点,其中有一个是\(p_i\), 那么这一步可能会带来一次\(\rm{rebuild}\), 即只会对最大值有贡献。

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<bitset>
#include<math.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
const int N=100000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u];i;i=sq[i].nxt)
#define fir first
#define sec second
#define mp make_pair
#define pb push_back
#define maxd 998244353
#define eps 1e-8
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*10+(ch-'0');ch=getchar();}
    return x*f;
}

namespace My_Math{
	#define N 100000

	int fac[N+100],invfac[N+100];

	int add(int x,int y) {return x+y>=maxd?x+y-maxd:x+y;}
	int dec(int x,int y) {return x<y?x-y+maxd:x-y;}
	int mul(int x,int y) {return 1ll*x*y%maxd;}
	ll qpow(ll x,int y)
	{
		ll ans=1;
		while (y)
		{
			if (y&1) ans=mul(ans,x);
			x=mul(x,x);y>>=1;
		}
		return ans;
	}
	int inv(int x) {return qpow(x,maxd-2);}

	int C(int n,int m)
	{
		if ((n<m) || (n<0) || (m<0)) return 0;
		return mul(mul(fac[n],invfac[m]),invfac[n-m]);
	}

	int math_init()
	{
		fac[0]=invfac[0]=1;
		rep(i,1,N) fac[i]=mul(fac[i-1],i);
		invfac[N]=inv(fac[N]);
		per(i,N-1,1) invfac[i]=mul(invfac[i+1],i+1);
	}
	#undef N
}
using namespace My_Math;
struct edgenode{int u,v;}edge[200200];
struct node{int to,nxt;}sq[200200];
int all=0,head[200200];
void addedge(int u,int v){all++;sq[all].to=v;sq[all].nxt=head[u];head[u]=all;}
int d[200200],dis[200200],n,m,k,p[200200];
bool vis[200200],must[200200];
vector<int> sq2[200200]; 
struct hnode{int u,dis;};
bool operator <(hnode p,hnode q) {return p.dis>q.dis;}
priority_queue<hnode> q;

void dij(int st)
{
	//cout << "start " << st << endl;
	memset(dis,0x3f,sizeof(dis));
	dis[st]=0;q.push((hnode){st,0});
	while (!q.empty())
	{
		int u=q.top().u;q.pop();
		if (vis[u]) continue;vis[u]=1;
		go(u,i)
		{
			int v=sq[i].to;
			if (dis[v]>dis[u]+1)
			{
				dis[v]=dis[u]+1;
				if (!vis[v]) q.push((hnode){v,dis[v]});
			}
		}
	}
	//rep(i,1,n) cout << dis[i] << " ";cout << endl;
	rep(i,1,m)
	{
		int u=edge[i].u,v=edge[i].v;
		if (dis[v]+1==dis[u]) sq2[u].pb(v);
	}
	rep(i,1,n) d[i]=(int)sq2[i].size();
	rep(i,1,k-1)
	{
		int u=p[i];must[i]=1;
		rep(j,0,d[u]-1)
			if (sq2[u][j]==p[i+1]) must[i]=0;
	}
} 

int main()
{
	n=read();m=read();
	rep(i,1,m)
	{
		edge[i].u=read();edge[i].v=read();
		addedge(edge[i].v,edge[i].u);
	}
	k=read();
	rep(i,1,k) p[i]=read();
	dij(p[k]);
	int cnt=0,mx=0,mn=0;
	rep(i,1,k-1)
	{
		if (must[i]) cnt++;
		else if (d[p[i]]>1) mx++;
	}
	mx+=cnt;mn+=cnt;
	cout << mn << " " << mx << endl;
	return 0;
}

DIV2E/DIV1C

从小到大枚举武器,同时维护每个防具的答案。

怪物按照防御值排序,随着武器的枚举而计算贡献,发现每个怪物对防具的贡献都是后缀加的形式,直接线段树维护即可。

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<bitset>
#include<math.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
const int N=100000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u];i;i=sq[i].nxt)
#define fir first
#define sec second
#define mp make_pair
#define pb push_back
#define maxd 998244353
#define eps 1e-8
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*10+(ch-'0');ch=getchar();}
    return x*f;
}

namespace My_Math{
	#define N 100000

	int fac[N+100],invfac[N+100];

	int add(int x,int y) {return x+y>=maxd?x+y-maxd:x+y;}
	int dec(int x,int y) {return x<y?x-y+maxd:x-y;}
	int mul(int x,int y) {return 1ll*x*y%maxd;}
	ll qpow(ll x,int y)
	{
		ll ans=1;
		while (y)
		{
			if (y&1) ans=mul(ans,x);
			x=mul(x,x);y>>=1;
		}
		return ans;
	}
	int inv(int x) {return qpow(x,maxd-2);}

	int C(int n,int m)
	{
		if ((n<m) || (n<0) || (m<0)) return 0;
		return mul(mul(fac[n],invfac[m]),invfac[n-m]);
	}

	int math_init()
	{
		fac[0]=invfac[0]=1;
		rep(i,1,N) fac[i]=mul(fac[i-1],i);
		invfac[N]=inv(fac[N]);
		per(i,N-1,1) invfac[i]=mul(invfac[i+1],i+1);
	}
	#undef N
}
using namespace My_Math;
struct node{int v,c;}atk[200200],def[200200],atk1[200200],def1[200200];
bool operator <(node p,node q)
{
	return ((p.v<q.v) || ((p.v==q.v) && (p.c<q.c)));
}
struct mnode{int a,d,z;}mon[200200];
bool operator <(mnode p,mnode q) {return p.d<q.d;}
int n,m,p,x[200200];
ll tag[4004000],seg[4004000];

void build(int id,int l,int r)
{
	if (l==r) {seg[id]=-def[l].c;return;}
	int mid=(l+r)>>1;
	build(id<<1,l,mid);build(id<<1|1,mid+1,r);
	seg[id]=max(seg[id<<1],seg[id<<1|1]);
}

void pushdown(int id)
{
	if (tag[id])
	{
		seg[id<<1]+=tag[id];seg[id<<1|1]+=tag[id];
		tag[id<<1]+=tag[id];tag[id<<1|1]+=tag[id];
		tag[id]=0;
	}
}

void modify(int id,int l,int r,int ql,int qr,int val)
{
	if ((l>=ql) && (r<=qr)) 
	{
		seg[id]+=val;tag[id]+=val;
		return;
	}
	pushdown(id);
	int mid=(l+r)>>1;
	if (ql<=mid) modify(id<<1,l,mid,ql,qr,val);
	if (qr>mid) modify(id<<1|1,mid+1,r,ql,qr,val);
	seg[id]=max(seg[id<<1],seg[id<<1|1]);
}

int main()
{
	n=read();m=read();p=read();
	rep(i,1,n) {atk1[i].v=read();atk1[i].c=read();}
	rep(i,1,m) {def1[i].v=read();def1[i].c=read();}
	sort(def1+1,def1+1+m);
	sort(atk1+1,atk1+1+n);
	int tp=0;
	memset(seg,-0x3f,sizeof(seg));
	rep(i,1,n) 
		if (atk1[i].v!=atk[tp].v) atk[++tp]=atk1[i];
	n=tp;tp=0;
	rep(i,1,m)
		if (def1[i].v!=def[tp].v) def[++tp]=def1[i];
	m=tp;
	rep(i,1,p)
	{
		mon[i].d=read();mon[i].a=read();mon[i].z=read();
	}
	rep(i,1,m) x[i]=def[i].v;
	//cout << endl;
	//rep(i,1,m) cout << x[i] << " " << def[i].c << endl; 
	sort(mon+1,mon+1+p);
	build(1,1,m);
	ll ans=-1e18;int pos=1;
	rep(i,1,n)
	{
		while ((pos<=p) && (atk[i].v>mon[pos].d))
		{
			int p1=upper_bound(x+1,x+1+m,mon[pos].a)-x;
			if (mon[pos].a<x[m]) 
				modify(1,1,m,p1,m,mon[pos].z);
			pos++;
		}
		ans=max(ans,seg[1]-atk[i].c);
	}
	cout << ans;
	return 0;
}

DIV2F/DIV1D

发现每个操作的可以将一个\(0\)向前或向后移\(2\)位,也就是不会改变其下标的奇偶性。

同时又注意到形如\(00\)这样的串,两个\(0\)都互相无法越过对方。

所以判断两个子串是否能变成一致的条件就是:两个子串中\(0\)的下标的奇偶性均相同。

把这个变成一个字符串的形式,直接上哈希就行了(反正没人来得及叉)

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<bitset>
#include<math.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
const int N=200000+100;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u];i;i=sq[i].nxt)
#define fir first
#define sec second
#define mp make_pair
#define pb push_back
#define maxd 1000000009
#define eps 1e-8
#define bas 233
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*10+(ch-'0');ch=getchar();}
    return x*f;
}

ll hsh[N][2],pw[N];
int n,q,cnt[N];
char s[N];

ll query(int l,int r,int op)
{
	ll now=hsh[r][op]-hsh[l-1][op]*pw[cnt[r]-cnt[l-1]];
	return (now%maxd+maxd)%maxd;
}

int main()
{
	n=read();
	scanf("%s",s+1);
	hsh[0][0]=hsh[1][0]=1;
	rep(i,1,n)
	{
		hsh[i][0]=hsh[i-1][0];hsh[i][1]=hsh[i-1][1];cnt[i]=cnt[i-1];
		if (s[i]=='0')
		{
			hsh[i][0]=(hsh[i][0]*bas+'0'+(i&1))%maxd;
			hsh[i][1]=(hsh[i][1]*bas+'0'+((i&1)^1))%maxd;
			cnt[i]++;
		}
	}
	pw[0]=1;
	rep(i,1,n) pw[i]=pw[i-1]*bas%maxd;
	q=read();
	while (q--)
	{
		int l1=read(),l2=read(),len=read();
		int r1=l1+len-1,r2=l2+len-1;
		if (query(l1,r1,l1&1)==query(l2,r2,l2&1)) puts("Yes");
		else puts("No");
	}
	return 0;
}

DIV1F

把虚树已经写在脸上的题目(但是我早就忘记怎么写了)

发现虚树上每条路径上被隐去的点必然会被染上同一种病毒,于是虚树的合法性就有了,接下来写一个多源dijkstra就好了。

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<bitset>
#include<math.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
const int N=200000+100;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u];i;i=sq[i].nxt)
#define fir first
#define sec second
#define mp make_pair
#define pb push_back
#define maxd 998244353
#define eps 1e-8
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*10+(ch-'0');ch=getchar();}
    return x*f;
}

namespace My_Math{
	#define N 100000

	int fac[N+100],invfac[N+100];

	int add(int x,int y) {return x+y>=maxd?x+y-maxd:x+y;}
	int dec(int x,int y) {return x<y?x-y+maxd:x-y;}
	int mul(int x,int y) {return 1ll*x*y%maxd;}
	ll qpow(ll x,int y)
	{
		ll ans=1;
		while (y)
		{
			if (y&1) ans=mul(ans,x);
			x=mul(x,x);y>>=1;
		}
		return ans;
	}
	int inv(int x) {return qpow(x,maxd-2);}

	int C(int n,int m)
	{
		if ((n<m) || (n<0) || (m<0)) return 0;
		return mul(mul(fac[n],invfac[m]),invfac[n-m]);
	}

	int math_init()
	{
		fac[0]=invfac[0]=1;
		rep(i,1,N) fac[i]=mul(fac[i-1],i);
		invfac[N]=inv(fac[N]);
		per(i,N-1,1) invfac[i]=mul(invfac[i+1],i+1);
	}
	#undef N
}
using namespace My_Math;
struct sqnode{int to,nxt;}sq[N<<1];
int all=0,head[N];
int tp[N],fa[N],siz[N],dep[N],tim=0,dfn[N],son[N];
int n,m,k,ans[N],ask[N];
struct virus{int id,spd;}vir[N];

void addedge(int u,int v)
{
	all++;sq[all].nxt=head[u];sq[all].to=v;head[u]=all;
}

void dfs1(int u,int fu)
{
	fa[u]=fu;siz[u]=1;dep[u]=dep[fu]+1;dfn[u]=(++tim);
	go(u,i)
	{
		int v=sq[i].to;
		if (v==fu) continue;
		dfs1(v,u);siz[u]+=siz[v];
		if (siz[v]>siz[son[u]]) son[u]=v;
	}
}

void dfs2(int u,int tpu)
{
	tp[u]=tpu;
	if (son[u]) dfs2(son[u],tpu);
	go(u,i)
	{
		int v=sq[i].to;
		if ((v==fa[u]) || (v==son[u])) continue;
		dfs2(v,v);
	}
}

int query(int u,int v)
{
	while (tp[u]!=tp[v])
	{
		if (dep[tp[u]]<dep[tp[v]]) swap(u,v);
		u=fa[tp[u]];
	}
	if (dep[u]>dep[v]) swap(u,v);
	return u;
}

vector<pii> tr[N];
int sta[N];
vector<int> used;

void addedgetr(int u,int v)
{
	int dis=abs(dep[u]-dep[v]);
	//cout << "add " << u << " " << v << " " << dis << endl;
	tr[u].pb(mp(v,dis));tr[v].pb(mp(u,dis));
}

bool cmp(int u,int v) {return dfn[u]<dfn[v];}

void virtual_tree(vector<int> p)
{
	sort(p.begin(),p.end(),cmp);
	int len=unique(p.begin(),p.end())-p.begin();
	int tp=0;used.clear();
	//cout << "vtree ";
	//rep(i,0,len-1) cout << p[i] << " ";cout << endl;
	rep(i,0,len-1)
	{
		int u=p[i];used.pb(u);
		if (!tp) {sta[++tp]=u;continue;}
		int lca=query(u,sta[tp]);
		while ((tp) && (dep[sta[tp-1]]>=dep[lca])) {addedgetr(sta[tp-1],sta[tp]);tp--;}
		if (sta[tp]!=lca) {addedgetr(sta[tp],lca);sta[tp]=lca;used.pb(lca);}
		sta[++tp]=u;
	}
	while (tp>1)
	{
		addedgetr(sta[tp],sta[tp-1]);
		tp--;
	}
}

struct hnode{int dis,tim,u,vid;};
bool operator <(hnode p,hnode q)
{
	if (p.tim==q.tim) return p.vid>q.vid;
	else return p.tim>q.tim;
}
priority_queue<hnode> q;

void dij()
{
	rep(i,1,m)
		q.push((hnode){0,0,vir[i].id,i});
	while (!q.empty())
	{
		hnode now=q.top();q.pop();
		if (ans[now.u]) continue;
		ans[now.u]=now.vid;int len=tr[now.u].size();
		rep(i,0,len-1)
		{
			int v=tr[now.u][i].fir,d=tr[now.u][i].sec;
			if (!ans[v])
			{
				int t=(now.dis+d-1)/vir[now.vid].spd+1;
				q.push((hnode){now.dis+d,t,v,now.vid});
			}
		}
	}
}

int main()
{
	n=read();
	rep(i,1,n-1)
	{
		int u=read(),v=read();
		addedge(u,v);addedge(v,u);
	}
	dfs1(1,0);dfs2(1,1);
	int q=read();
	while (q--)
	{
		m=read();k=read();
		vector<int> p;p.clear();
		rep(i,1,m)
		{
			vir[i].id=read();vir[i].spd=read();
			p.pb(vir[i].id);
		}
		rep(i,1,k)
		{
			ask[i]=read();p.pb(ask[i]);
		}
		virtual_tree(p);
		dij();
		//printf("answer ");
		rep(i,1,k) printf("%d ",ans[ask[i]]);puts("");
		int len=used.size();
		rep(i,0,len-1) {ans[used[i]]=0;tr[used[i]].clear();}
	}
	return 0;
}

posted @ 2020-03-03 00:05  EncodeTalker  阅读(213)  评论(0编辑  收藏  举报