• 题解「CF891C Envy」


    很多题解对于 ( ext{MST}) 性质的描述,有些奇怪。

    以至于:

    咳咳,稍微打个岔(

    这题确实是个性质题
    我们先考虑只有一组询问的情况。将这组询问中的边按边权排序。对于当前的 (w_i) ,确保 (< w_i) 边权的边已被加入 ( ext{Kruskal}) 的贡献中,再尝试加入当前的 (w_i)。如果询问中有多个与 (w_i) 边权相同的边则全部试图加入,若其中一条无法加入则说明不可行。

    这样为什么是对的呢?对于所有的最小生成树,其中每种权值的边的数量是一定的。如果我们加入了 (<w_i) 的所有边(因为这些边中的一些边不加入进最小生成树只会得到更劣解)而使边权与 (w_i) 相同的边无法加入,则说明这条边不在最小生成树上。同样的,如果我们将询问中边权相同的边加入,其中有边无法加入,则说明他们无法同时存在于一棵最小生成树上。

    于是我们发现,对于一组询问中,不同边权之间其实并不存在影响。因为对于询问中的任意两条边 (w_i,w_j) ,不妨设 (w_i) 的边权 (<) (w_j) 的边权,那么所有 (<w_j) 边权的边(包括 (w_i))在此前都已被加入进 ( ext{Kruskal}) 的贡献中。

    根据上述结论,我们将每组询问拆成若干组边权相同的询问。对于每组边权相同的询问分别处理,然后统计其对每组询问的贡献。具体来说就是将每组边权相同的询问按询问中的边权排序,按只存在一次询问的做法处理这些询问,需要用上一些常规的离线技巧(

    值得注意的是,加入一组询问中边权相同的边后需要撤回这组边,因为可能会对后续询问产生影响。这需要我们使用一个支持 撤销上一次操作的并查集:用按秩合并实现能够保留树的结构,用栈记录修改信息,暴力修改,查询,撤销即可。

    代码写的非常生草,随便看看就好,嘤嘤嘤(

    Show the Code

    #include<cstdio>
    #include<vector>
    #include<algorithm>
    int top=0;
    std::vector<int> ask[500005];
    int x[500005],y[500005],z[500005],fa[500005],size[500005],tmp[500005],res[500005];
    struct edge {int x,y,val;} e[500005]; 
    struct state {int x,y,fx,fy;} st[500005];
    inline int read() {
    	register int x=0,f=1;register char s=getchar();
    	while(s>'9'||s<'0') {if(s=='-') f=-1;s=getchar();}
    	while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
    	return x*f;
    }
    inline void swap(int &x,int &y) {int tmp=y;y=x;x=tmp;}
    inline bool cmp1(const edge &x,const edge &y) {return x.val<y.val;}
    inline bool cmp2(const int &x,const int &y) {return z[x]<z[y];}
    inline bool cmp3(const std::vector<int> &x,const std::vector<int> &y) {return z[x[1]]<z[y[1]];}
    inline int find(int x) {while(x!=fa[x]) x=fa[x]; return x;}
    inline void merge(int x,int y) {
    	int fx=find(x),fy=find(y);
    	if(fx!=fy) {
    		if(size[fx]>size[fy]) swap(fx,fy);
    		st[++top]=(state){x,y,fx,fy};
    		size[fy]+=size[fx]; fa[fx]=fy;
    	} 
    }
    int main() {
    	int n=read(),m=read(),num=0,cur=1,Q=0;
    	for(register int i=1;i<=n;++i) {fa[i]=i;size[i]=1;}
    	for(register int i=1;i<=m;++i) {
    		x[i]=read();y[i]=read();z[i]=read();
    		e[i].x=x[i];e[i].y=y[i];e[i].val=z[i];
    	}
    	std::sort(e+1,e+1+m,cmp1); Q=read();
    	for(register int t=1;t<=Q;++t) {
    		int len=read(); res[t]=1;
    		for(register int i=1;i<=len;++i) tmp[i]=read();
    		std::sort(tmp+1,tmp+1+len,cmp2);
    		for(register int i=1;i<=len;++i) {
    			if(z[tmp[i]]!=z[tmp[i-1]]) ask[++num].push_back(t);
    			ask[num].push_back(tmp[i]);
    		}
    	}
    	std::sort(ask+1,ask+1+num,cmp3);
    	for(register int i=1;i<=num;++i) {
    		int flag=1;
    		while(cur<=m&&e[cur].val<z[ask[i][1]]) {merge(e[cur].x,e[cur].y); ++cur;}
    		for(register int j=1;j<ask[i].size();++j) {int id=ask[i][j]; if(find(x[id])==find(y[id])) {flag=0;} else {merge(x[id],y[id]);}}
    		for(register int j=ask[i].size()-1;j>=1;--j) {
    			int id=ask[i][j]; while(top>0&&st[top].x==x[id]&&st[top].y==y[id]) {fa[st[top].fx]=st[top].fx;size[st[top].fy]-=size[st[top].fx];--top;}
    		} 
    		res[ask[i][0]]&=flag;
    	}
    	for(register int t=1;t<=Q;++t) printf("%s
    ",res[t]? "YES":"NO");
    	return 0;
    }
    
  • 相关阅读:
    PDI的steps:(8:Avro input)
    Expert Cube Development with Microsoft SQL Server 2008 Analysis Services(1)
    PDI的steps:(6:Analytic Query)
    PDI的steps:(5:Add value fields changing sequence)
    Junk dimensions
    PDI的steps:(8:Automatic Documentation Output)
    PDI的steps:(5:Add XML)
    PDI的steps:(7:Append streams)
    Expert Cube Development with Microsoft SQL Server 2008 Analysis Services(2)度量值和度量值组
    Expert Cube Development with Microsoft SQL Server 2008 Analysis Services(3) 第一章
  • 原文地址:https://www.cnblogs.com/tommy0103/p/13752880.html
Copyright © 2020-2023  润新知