zoukankan      html  css  js  c++  java
  • P5618 [SDOI2015]道路修建 题解

    Luogu

    Description.

    有一个 \(2\times n\) 的网格,有 \(3\times n-2\) 条边。
    需要支持边权修改,以及求区间最小生成树。

    Solution.

    没想到线段树

    就是考虑区间合并时,会多出来两条边,再找到最大的那条边删掉。
    由于最小生成树必定存在
    线段树强上。
    分别维护

    右边两条横边、选了几条竖边,最左边和最右边的竖边边权,左边、右边一圈的最小值,最小横边,答案
    

    然后直接暴力维护即可。

    Coding.

    //是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
    #include<bits/stdc++.h>
    using namespace std;typedef long long ll;
    template<typename T>inline void read(T &x)
    {
    	x=0;char c=getchar(),f=0;
    	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
    	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    	f?x=-x:x;
    }/*}}}*/
    const int N=60005;
    int n,m,hg[N][2],rw[N];
    struct node
    {
    	int rhg0,rhg1,cnt,lsh,rsh,lvl,rvl,mx;ll res;
    	//分别为右边两条横边、选了几条竖边,最左边和最右边的竖边边权
    	//左边、右边一圈的最小值,最小横边,答案
    	inline node operator+(node b)
    	{
    		node a=*this,r;r.rhg0=b.rhg0,r.rhg1=b.rhg1,r.rsh=b.rsh,r.lsh=a.lsh;
    		int a1=a.rhg0,a2=a.rhg1,b1=a.rvl,b2=b.lvl,mx;
    		mx=max(max(a1,a2),max(b1,b2)),r.mx=max(max(a1,a2),max(a.mx,b.mx));
    		r.res=a.res+b.res+a1+a2-mx,r.lvl=a.lvl,r.rvl=b.rvl,r.cnt=a.cnt+b.cnt;
    		if(mx==b1)
    		{
    			if(a.rsh!=b1) return r;else if(a.cnt>1) return r.cnt--,r;
    			return r.cnt--,r.lsh=b.lsh,r.lvl=max(max(b.lvl,a.mx),max(a1,a2)),r;
    		}
    		if(mx==b2)
    		{
    			if(b.lsh!=b2) return r;else if(b.cnt>1) return r.cnt--,r;
    			return r.cnt--,r.rsh=a.rsh,r.rvl=max(max(a.rvl,b.mx),max(a1,a2)),r;
    		}
    		return r;
    	}
    }T[N<<2];
    inline node init(int x) {return(node){hg[x][0],hg[x][1],1,rw[x],rw[x],rw[x],rw[x],0,rw[x]};}
    inline void pt(node x) {printf("%d,%d %d %d,%d,%d,%d %d ! %lld\n",x.rhg0,x.rhg1,x.cnt,x.lsh,x.rsh,x.lvl,x.rvl,x.mx,x.res);}
    inline void build(int x,int l,int r)
    {
    	if(l==r) return T[x]=init(l),void();
    	build(x<<1,l,(l+r)>>1),build(x<<1|1,((l+r)>>1)+1,r),T[x]=T[x<<1]+T[x<<1|1];
    	//pt(T[x<<1]),pt(T[x<<1|1]),pt(T[x]),putchar('\n');
    }
    inline void updat(int x,int l,int r,int dw)
    {
    	if(l==r) return T[x]=init(l),void();
    	if(dw<=((l+r)>>1)) updat(x<<1,l,(l+r)>>1,dw),T[x]=T[x<<1]+T[x<<1|1];
    	else updat(x<<1|1,((l+r)>>1)+1,r,dw),T[x]=T[x<<1]+T[x<<1|1];
    }
    inline node query(int x,int l,int r,int dl,int dr)
    {
    	int md;if(dl<=l&&r<=dr) return T[x];else md=(l+r)>>1;
    	if(dl>md) return query(x<<1|1,md+1,r,dl,dr);
    	else if(md>=dr) return query(x<<1,l,md,dl,dr);
    	return query(x<<1,l,md,dl,dr)+query(x<<1|1,md+1,r,dl,dr);
    }
    int main()
    {
    	read(n),read(m);for(int i=1;i<n;i++) read(hg[i][0]);
    	for(int i=1;i<n;i++) read(hg[i][1]);
    	for(int i=1;i<=n;i++) read(rw[i]);
    	build(1,1,n);for(int x1,y1,x2,y2,vl;m--;)
    	{
    		char fg[5];scanf("%s",fg),read(x1);
    		if(*fg=='Q') read(x2),printf("%lld\n",query(1,1,n,min(x1,x2),max(x1,x2)).res);
    		else
    		{
    			read(y1),read(x2),read(y2),read(vl);
    			if(y1==y2) rw[y1]=vl,updat(1,1,n,y1);
    			else hg[min(y1,y2)][x1-1]=vl,updat(1,1,n,min(y1,y2));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    cl编译器命令行调试问题
    西电计算机专业培养
    GCN代码实现
    GCN介绍
    cpu密集型任务及IO密集型任务,GIS,多进程及多线程
    骨架提取
    视频文件的一些属性
    空洞填充
    凸包,二值图家矩形框
    RGB图片取大于阈值部分
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15041599.html
Copyright © 2011-2022 走看看