zoukankan      html  css  js  c++  java
  • BZOJ 2001: [Hnoi2010]City 城市建设

    好鬼的CDQ分治,感觉复杂度好迷的说感觉就是个剪枝的暴力

    首先看到题目,动态MST,妈妈我会线段树分治+LCT然后这题就做完了

    大体上很套路,我们把修改看作一条边的删除以及一条新边的加入,就可以求出每条边出现的时间区间

    然后按时间为下标建线段树,我们只要能实现插入一条边/撤销即可,然后我们发现这个东西可以很容易LCT维护,每次找出成环的路径上的最大值然后替换掉即可

    总体复杂度(O(nlog^2 n)),据说常数巨大(我不想写),因此这里讲一种抄来的玄学CDQ分治的做法

    首先我们要明确CDQ的本质:讲可以一些操作间重复的部分最大化,然后解决这个重复部分

    考虑我们现在处理的区间是([l,r]),那么对于不被这个区间操作影响的边(姑且称为静态边),显然我们可以找出其中一些必须选的边和一些肯定不选的边,然后再往下递归的时候就不用考虑它们

    那具体怎么处理呢,我们考虑进行以下操作:

    1. 将现在分治的区间内的所有边(姑且称为动态边),边权设为(-infty),然后跑一遍MST,然后我们找出MST上的所有静态边(边权不为(-infty)),它们显然是必选的
    2. 将现在分治的区间内的所有边,边权设为(infty),然后跑一遍MST,然后我们找出没有出现在MST上的所有静态边(边权不为(infty)),它们显然是无用的

    然后我们把所有的必选边先连起来,然后往下处理的时候忽略掉无用边

    根据某种神奇的力量(或者感性理解),这样每次处理的边数会减半(会证明的老哥麻烦告诉我下证明),因此总复杂度就是(O(nlog^2 n))的,但是常数极小(分治+排序),不像某两大常数算法的结合

    #include<cstdio>
    #include<cctype>
    #include<vector>
    #include<algorithm>
    #define RI register int
    #define CI const int&
    #define Tp template <typename T>
    #define pb push_back
    using namespace std;
    typedef long long LL;
    const int N=50005,INF=1e9;
    struct edge
    {
    	int x,y,w,id;
    	friend inline bool operator < (const edge& A,const edge& B)
    	{
    		return A.w<B.w;
    	}
    }ne[N],tp[N],nw; vector <edge> E[20]; int n,m,q,val[N],px[N],py[N],pos[N]; LL ans[N];
    class FileInputOutput
    {
    	private:
    		static const int S=1<<21;
    		#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
    		#define pc(ch) (Ftop!=Fend?*Ftop++=ch:(fwrite(Fout,1,S,stdout),*(Ftop=Fout)++=ch))
    		char Fin[S],Fout[S],*A,*B,*Ftop,*Fend; int pt[25];
    	public:
    		inline FileInputOutput(void) { Ftop=Fout; Fend=Fout+S; }
    		Tp inline void read(T& x)
    		{
    			x=0; char ch; while (!isdigit(ch=tc()));
    			while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
    		}
    		Tp inline void write(T x)
    		{
    			RI ptop=0; while (pt[++ptop]=x%10,x/=10);
    			while (ptop) pc(pt[ptop--]+48); pc('
    ');
    		}
    		inline void flush(void)
    		{
    			fwrite(Fout,1,Ftop-Fout,stdout);
    		}
    		#undef tc
    		#undef pc
    }F;
    class UnionFindSet
    {
    	private:
    		int fa[N];
    	public:
    		inline void init(CI n,edge *e)
    		{
    			for (RI i=0;i<n;++i) fa[e[i].x]=e[i].x,fa[e[i].y]=e[i].y;
    		}
    		inline int getfa(CI x)
    		{
    			return fa[x]!=x?fa[x]=getfa(fa[x]):x;
    		}
    		inline bool identify(CI x,CI y)
    		{
    			return getfa(x)==getfa(y);
    		}
    		inline void Union(CI x,CI y)
    		{
    			fa[getfa(x)]=getfa(y);
    		}
    }UFS;
    inline void retain(int& n,LL& sum)
    {
    	RI i,cnt=0; for (UFS.init(n,ne),sort(ne,ne+n),i=0;i<n;++i)
    	if (!UFS.identify(ne[i].x,ne[i].y)) UFS.Union(ne[i].x,ne[i].y),tp[cnt++]=ne[i];
    	for (UFS.init(cnt,tp),i=0;i<cnt;++i) if (tp[i].w!=-INF)
    	if (!UFS.identify(tp[i].x,tp[i].y)) UFS.Union(tp[i].x,tp[i].y),sum+=tp[i].w;
    	for (cnt=i=0;i<n;++i) if (!UFS.identify(ne[i].x,ne[i].y))
    	tp[cnt++]=(edge){UFS.getfa(ne[i].x),UFS.getfa(ne[i].y),ne[i].w,ne[i].id};
    	for (i=0;i<cnt;++i) pos[ne[i].id]=i,ne[i]=tp[i]; n=cnt;
    }
    inline void remove(int& n)
    {
    	RI i,cnt=0; for (UFS.init(n,ne),sort(ne,ne+n),i=0;i<n;++i)
    	if (!UFS.identify(ne[i].x,ne[i].y)) UFS.Union(ne[i].x,ne[i].y),tp[cnt++]=ne[i];
    	else if (ne[i].w==INF) tp[cnt++]=ne[i];
    	for (i=0;i<cnt;++i) pos[ne[i].id]=i,ne[i]=tp[i]; n=cnt;
    }
    inline void solve(CI l=1,CI r=q,CI dep=0,LL sum=0)
    {
    	int n=E[dep].size(); RI i; if (l==r) val[px[l]]=py[l];
    	for (i=0;i<n;++i) E[dep][i].w=val[E[dep][i].id],ne[i]=E[dep][i],pos[ne[i].id]=i;
    	if (l==r)
    	{
    		for (ans[l]=sum,UFS.init(n,ne),sort(ne,ne+n),i=0;i<n;++i)
    		if (!UFS.identify(ne[i].x,ne[i].y)) UFS.Union(ne[i].x,ne[i].y),ans[l]+=ne[i].w; return;
    	}
    	for (i=l;i<=r;++i) ne[pos[px[i]]].w=-INF; retain(n,sum);
    	for (i=l;i<=r;++i) ne[pos[px[i]]].w=INF; remove(n);
    	for (E[dep+1].clear(),i=0;i<n;++i) E[dep+1].pb(ne[i]);
    	int mid=l+r>>1; solve(l,mid,dep+1,sum); solve(mid+1,r,dep+1,sum);
    }
    int main()
    {
    	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    	RI i; for (F.read(n),F.read(m),F.read(q),i=1;i<=m;++i)
    	F.read(nw.x),F.read(nw.y),F.read(nw.w),val[i]=nw.w,nw.id=i,E[0].pb(nw);
    	for (i=1;i<=q;++i) F.read(px[i]),F.read(py[i]);
    	for (solve(),i=1;i<=q;++i) F.write(ans[i]); return F.flush(),0;
    }
    
  • 相关阅读:
    Linux零碎知识
    Xshell连接不上Linux
    Python中获取当前时间 获取当前时间前几天的代码
    重新设置Linux文件共享密码..
    【Python】【解决】UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 1: ordinal not in range(128)
    应该怎么理解 app = Flask(__name__)
    刚才在windows下发现拖拽不了文件了
    Hadoop点滴-何时使用hadoop fs、hadoop dfs与hdfs dfs命令
    Hadoop点滴-Hadoop分布式文件系统
    Hadoop点滴-初识MapReduce(2)
  • 原文地址:https://www.cnblogs.com/cjjsb/p/12260586.html
Copyright © 2011-2022 走看看