ZOJ

题意:一棵树上有m个红色结点,树的边有权值。q次查询,每次给出k个点,每次查询有且只有一次机会将n个点中任意一个点染红,令k个点中距离红色祖先距离最大的那个点的距离最小化。q次查询相互独立。
分析:数据量很... 最大值最小化,二分搜答案。将ST表求lca的dfs函数加一点东西,求出每个点到其最近红色祖先的距离。check函数中,枚举到其红色祖先的距离超过下限的点。设非法点数为p,尝试将其距离通过一次染色缩小。具体做法是求出这p个点的lca,这个点就是要染红的点,因为只有修改这个点,才有可能将所有点的红祖先距离都缩减。若修改之后仍有结点非法,则check失败

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100005;
struct node{
	int v,next;
	LL dis;
}edges[N<<1];
int head[N],e;
int id[N]; //节点第一次被遍历的顺序
LL dis[N]; //节点到根节点的距离
LL rdis[N]; //距离最近的红色祖先的距离
bool red[N];
int RMQ[N*2][20];
int curID;
//F[i]表示第i个遍历的节点
//B[i]表示F[i]在树中的深度
int F[N*2],B[N*2];
int n,m,Q,root;
#include<bits/stdc++.h>
using namespace std;
////////////////
namespace IO {
#define BUF_SIZE 100000
#define OUT_SIZE 100000
#define ll long long
    //fread->read

    bool IOerror = 0;
    inline char nc() {
        static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
        if (p1 == pend) {
            p1 = buf; pend = buf + fread(buf, 1, BUF_SIZE, stdin);
            if (pend == p1) { IOerror = 1; return -1; }
            //{printf("IO error!
");system("pause");for (;;);exit(0);}
        }
        return *p1++;
    }
    inline bool blank(char ch) { return ch == ' ' || ch == '
' || ch == '
' || ch == '	'; }
    inline void read(int &x) {
        bool sign = 0; char ch = nc(); x = 0;
        for (; blank(ch); ch = nc());
        if (IOerror)return;
        if (ch == '-')sign = 1, ch = nc();
        for (; ch >= '0'&&ch <= '9'; ch = nc())x = x * 10 + ch - '0';
        if (sign)x = -x;
    }
    inline void read(ll &x) {
        bool sign = 0; char ch = nc(); x = 0;
        for (; blank(ch); ch = nc());
        if (IOerror)return;
        if (ch == '-')sign = 1, ch = nc();
        for (; ch >= '0'&&ch <= '9'; ch = nc())x = x * 10 + ch - '0';
        if (sign)x = -x;
    }
    inline void read(double &x) {
        bool sign = 0; char ch = nc(); x = 0;
        for (; blank(ch); ch = nc());
        if (IOerror)return;
        if (ch == '-')sign = 1, ch = nc();
        for (; ch >= '0'&&ch <= '9'; ch = nc())x = x * 10 + ch - '0';
        if (ch == '.') {
            double tmp = 1; ch = nc();
            for (; ch >= '0'&&ch <= '9'; ch = nc())tmp /= 10.0, x += tmp * (ch - '0');
        }
        if (sign)x = -x;
    }
    inline void read(char *s) {
        char ch = nc();
        for (; blank(ch); ch = nc());
        if (IOerror)return;
        for (; !blank(ch) && !IOerror; ch = nc())*s++ = ch;
        *s = 0;
    }
    inline void read(char &c) {
        for (c = nc(); blank(c); c = nc());
        if (IOerror) { c = -1; return; }
    }
    //fwrite->write
    struct Ostream_fwrite {
        char *buf, *p1, *pend;
        Ostream_fwrite() { buf = new char[BUF_SIZE]; p1 = buf; pend = buf + BUF_SIZE; }
        void out(char ch) {
            if (p1 == pend) {
                fwrite(buf, 1, BUF_SIZE, stdout); p1 = buf;
            }
            *p1++ = ch;
        }
        void print(int x) {
            static char s[15], *s1; s1 = s;
            if (!x)*s1++ = '0'; if (x<0)out('-'), x = -x;
            while (x)*s1++ = x % 10 + '0', x /= 10;
            while (s1-- != s)out(*s1);
        }
        void println(int x) {
            static char s[15], *s1; s1 = s;
            if (!x)*s1++ = '0'; if (x<0)out('-'), x = -x;
            while (x)*s1++ = x % 10 + '0', x /= 10;
            while (s1-- != s)out(*s1); out('
');
        }
        void print(ll x) {
            static char s[25], *s1; s1 = s;
            if (!x)*s1++ = '0'; if (x<0)out('-'), x = -x;
            while (x)*s1++ = x % 10 + '0', x /= 10;
            while (s1-- != s)out(*s1);
        }
        void println(ll x) {
            static char s[25], *s1; s1 = s;
            if (!x)*s1++ = '0'; if (x<0)out('-'), x = -x;
            while (x)*s1++ = x % 10 + '0', x /= 10;
            while (s1-- != s)out(*s1); out('
');
        }
        void print(double x, int y) {
            static ll mul[] = { 1,10,100,1000,10000,100000,1000000,10000000,100000000,
                1000000000,10000000000LL,100000000000LL,1000000000000LL,10000000000000LL,
                100000000000000LL,1000000000000000LL,10000000000000000LL,100000000000000000LL };
            if (x<-1e-12)out('-'), x = -x; x *= mul[y];
            ll x1 = (ll)floor(x); if (x - floor(x) >= 0.5)++x1;
            ll x2 = x1 / mul[y], x3 = x1 - x2 * mul[y]; print(x2);
            if (y>0) { out('.'); for (size_t i = 1; i<y&&x3*mul[i]<mul[y]; out('0'), ++i); print(x3); }
        }
        void println(double x, int y) { print(x, y); out('
'); }
        void print(char *s) { while (*s)out(*s++); }
        void println(char *s) { while (*s)out(*s++); out('
'); }
        void flush() { if (p1 != buf) { fwrite(buf, 1, p1 - buf, stdout); p1 = buf; } }
        ~Ostream_fwrite() { flush(); }
    }Ostream;
    inline void print(int x) { Ostream.print(x); }
    inline void println(int x) { Ostream.println(x); }
    inline void print(char x) { Ostream.out(x); }
    inline void println(char x) { Ostream.out(x); Ostream.out('
'); }
    inline void print(ll x) { Ostream.print(x); }
    inline void println(ll x) { Ostream.println(x); }
    inline void print(double x, int y) { Ostream.print(x, y); }
    inline void println(double x, int y) { Ostream.println(x, y); }
    inline void print(char *s) { Ostream.print(s); }
    inline void println(char *s) { Ostream.println(s); }
    inline void println() { Ostream.out('
'); }
    inline void flush() { Ostream.flush(); }
#undef ll
#undef OUT_SIZE
#undef BUF_SIZE
};
using namespace IO;

void init()
{
    e = 0; curID = 0;
    memset(head,-1,sizeof(head));
	memset(red,0,sizeof(red));
}

void AddEdge (int u,int v,LL w)
{
	edges[e].v=v;
	edges[e].dis=w;
	edges[e].next=head[u];
	head[u]=e++;
}

void DFS (int u,int p,int Dep,LL d)
{
	int i,v;
	if(red[u]) d=0;
	curID++;
	rdis[u] = d;
	F[curID]=u;
	B[curID]=Dep;
	id[u]=curID;
	for (i=head[u];i!=-1;i=edges[i].next){
		v=edges[i].v;
		if (v==p) continue;
		dis[v]=dis[u] + edges[i].dis;
		DFS(v,u,Dep+1,d+edges[i].dis);
		curID++;
		F[curID]=u;
		B[curID]=Dep;
	}
}

void initRMQ ()
{
	int i,j,x,y;
	for (i=1;i<=curID;i++)
		RMQ[i][0]=i;
	for (j=1;(1<<j)<=curID;j++)
		for (i=1;i+(1<<j)-1<=curID;i++){
			x=RMQ[i][j-1];
			y=RMQ[i+(1<<(j-1))][j-1];
			RMQ[i][j]=B[x]<B[y]?x:y;
		}
}

int getLCA (int a,int b)
{
	int k,x,y;
	a=id[a];b=id[b];
	if (a>b)
		k=a,a=b,b=k;
	k = 31 - __builtin_clz(b-a+1);
	x=RMQ[a][k];
	y=RMQ[b-(1<<k)+1][k];
	return B[x]<B[y]?F[x]:F[y];
}

int qq[N],cnt;
int vz[N];

bool check(LL &x)
{
	int all =0;
	for(int i=0;i<cnt;++i){             //枚举超过限制的结点
		if(rdis[qq[i]]>x){
			vz[all++] = qq[i];
		}
	}
	if(all==0) return true;
	int lca = vz[0];
	for(int i=0;i<all;++i){             //求出所有非法结点的lca,这个lca就是要染色的点
		lca = getLCA(lca,vz[i]);
	}
	LL mx = 0;
	for(int i=0;i<all;++i){             //查看最长距离
        if(dis[vz[i]]-dis[lca]>x) return false;
	}
	return true;
}

int main()
{
	#ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    int T; read(T);
    while(T--){
		int n,M,Q;
		int u,v; LL w;
		LL up = 0;
        init();
		read(n), read(M), read(Q);
        //scanf("%d %d %d",&n,&M,&Q);
		for(int i=1;i<=M;++i){
			read(u);
			red[u] = 1;
        }
		red[1] = 1;
        for(int i=1;i<n;++i){
			//scanf("%d %d %lld",&u,&v,&w);
			read(u), read(v), read(w);
			AddEdge(u,v,w);
			AddEdge(v,u,w);
			up += w;
        }
		DFS(1,0,0,0);
		initRMQ();
		while(Q--){
			int k; 	read(k);//scanf("%d",&k);
			cnt = k;
			for(int i=0;i<k;++i){
				read(qq[i]);
				//scanf("%d",&qq[i]);
			}
			LL L =0,R = up,mid,ans = up;
			while(L<=R){
				mid = (L+R)>>1;
				if(check(mid)){
					ans = mid;
					R = mid-1;
				}
				else L =mid+1;
			}
			println(ans);
			//printf("%lld
",ans);
		}
    }
    return 0;
}
为了更好的明天
原文地址:https://www.cnblogs.com/xiuwenli/p/9676674.html