zoukankan      html  css  js  c++  java
  • 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}),那么这一步一定会带来一次( m{rebuild}).

    • (p_i)能到达多个点,其中有一个是(p_i), 那么这一步可能会带来一次( m{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;
    }
    
    
  • 相关阅读:
    一些比较水的题目
    oracle not in,not exists,minus 数据量大的时候的性能问题
    简单的oracle分页语句
    oracle 查询结果集运算
    Spring注解详解
    HTTP报头Accept 和 Content-Type的区别
    vue 实现分转元的 过滤器
    oracle or语句的坑
    CSS样式 让你的输入的小写自动变成大写。
    js 十分精确身份证验证
  • 原文地址:https://www.cnblogs.com/encodetalker/p/12399124.html
Copyright © 2011-2022 走看看