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;
}

猜你喜欢

转载自www.cnblogs.com/encodetalker/p/12399124.html