BZOJ 3995 Sdoi2015 道路修建 线段树
来源:互联网 发布:mac安装hexo 编辑:程序博客网 时间:2024/05/25 16:37
题目大意:给定一个2*n的网格图,多次改变某条边的权值或询问y坐标在[l,r]中的2*(r-l+1)个点的MST
这真是一道好题= =
我们用线段树维护每个区间内的MST
然后考虑合并
合并两个区间 我们会加入两条边 这样一定会形成一个环 切掉环上最大边 这题没了
然后就是一坨乱七八糟的细节讨论= =
首先最大边一定在图中的彩色部分内 绿色部分可以O(1)求 我们需要维护的是红色和蓝色部分
然后如果切掉的边是横边或者切掉的竖边不是区间唯一的竖边(如图中蓝色竖边) 那么红框和蓝框直接用左右区间的即可
但是如果切掉了区间唯一的竖边(图中红色竖边),那么就有些麻烦了
首先我们需要知道切掉的是不是竖边 因此我们要记录每个区间的MST上最左侧和最右侧的竖边的权值
然后还要记录区间内MST上竖边的数量
然后如果切掉了红色的竖边 那么左侧的框被更新成了【左区间所有横边】【绿色边】【蓝色边】的最大值
因此还要记录区间所有横边的最大长度
然后更新时候讨论一下……就没了……
P.S.终于把SDOI2015的六道题都搞完了 居然搞了整整一下午+一天 我是不是可以退役了QAQ
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define M 60600using namespace std;int n,m;int a[M][2],b[M];struct abcd{int l,r;//区间左右端点int sum;//MST的权值int max_val;//区间内所有横边的最大边权int cnt;//MST上竖边的个数int l_val,r_val;//左/右侧第一个竖边的权值int l_max,r_max;//左/右侧第一个竖边以左/右的所有树边的最大权值abcd() {}abcd(int pos){int x=b[pos];l=r=pos;sum=x;max_val=0;cnt=1;l_val=r_val=x;l_max=r_max=x;}friend abcd operator + (const abcd &x,const abcd &y){abcd re;re.l=x.l;re.r=y.r;re.max_val=max(max(a[x.r][0],a[x.r][1]),max(x.max_val,y.max_val));int max_val=max(max(a[x.r][0],a[x.r][1]),max(x.r_max,y.l_max));//环上最大边re.sum=x.sum+y.sum+a[x.r][0]+a[x.r][1]-max_val;re.cnt=x.cnt+y.cnt;re.l_val=x.l_val;re.r_val=y.r_val;re.l_max=x.l_max;re.r_max=y.r_max;if( x.r_val==max_val ){re.cnt--;if(x.cnt==1){re.l_val=y.l_val;re.l_max=max(max(x.max_val,y.l_max),max(a[x.r][0],a[x.r][1]));}}else if( y.l_val==max_val ){re.cnt--;if(y.cnt==1){re.r_val=x.r_val;re.r_max=max(max(y.max_val,x.r_max),max(a[x.r][0],a[x.r][1]));}}return re;}};struct Segtree{Segtree *ls,*rs;abcd status;void* operator new (size_t){static Segtree mempool[M<<1],*C=mempool;return C++;}void Build_Tree(int x,int y){int mid=x+y>>1;if(x==y){status=abcd(mid);return ;}(ls=new Segtree)->Build_Tree(x,mid);(rs=new Segtree)->Build_Tree(mid+1,y);status=ls->status+rs->status;}void Refresh1(int x,int y,int pos){int mid=x+y>>1;if(x==y){status=abcd(mid);return ;}if(pos<=mid)ls->Refresh1(x,mid,pos);elsers->Refresh1(mid+1,y,pos);status=ls->status+rs->status;}void Refresh2(int x,int y,int pos){int mid=x+y>>1;if(mid==pos){status=ls->status+rs->status;return ;}if(pos<=mid)ls->Refresh2(x,mid,pos);elsers->Refresh2(mid+1,y,pos);status=ls->status+rs->status;}abcd Query(int x,int y,int l,int r){int mid=x+y>>1;if(x==l&&y==r)return status;if(r<=mid)return ls->Query(x,mid,l,r);if(l>mid)return rs->Query(mid+1,y,l,r);return ls->Query(x,mid,l,mid) + rs->Query(mid+1,y,mid+1,r) ;}}*root=new Segtree;void Modify(int x0,int y0,int x1,int y1,int z){if(y0==y1)//修改了一条竖边{b[y0]=z;root->Refresh1(1,n,y0);}else//修改了一条横边{if(y0>y1) swap(y0,y1);a[y0][x0-1]=z;root->Refresh2(1,n,y0);}}int main(){int i,x0,y0,x1,y1,x,y,z;char p[10];cin>>n>>m;for(i=1;i<n;i++)scanf("%d",&a[i][0]);for(i=1;i<n;i++)scanf("%d",&a[i][1]);for(i=1;i<=n;i++)scanf("%d",&b[i]);root->Build_Tree(1,n);for(i=1;i<=m;i++){scanf("%s",p);if(p[0]=='C'){scanf("%d%d%d%d%d",&x0,&y0,&x1,&y1,&z);Modify(x0,y0,x1,y1,z);}else{scanf("%d%d",&x,&y);abcd ans=root->Query(1,n,x,y);printf("%d\n",ans.sum);}}return 0;}
0 0
- BZOJ 3995 Sdoi2015 道路修建 线段树
- BZOJ 3995 SDOI2015 道路修建
- BZOJ 3995: [SDOI2015]道路修建
- BZOJ 3995 [SDOI2015]道路修建
- 3995: [SDOI2015]道路修建
- 【BZOJ3995】【SDOI2015】道路修建
- bzoj 2435 道路修建
- BZOJ 2435 道路修建
- BZOJ 2435: [Noi2011]道路修建 树的遍历-_-
- BZOJ3995:道路修建(线段树维护MST)
- BZOJ 2435 NOI2011 道路修建 BFS/DFS
- 【BZOJ】【P2435】【Noi2011】【道路修建】【题解】【dfs】
- [BZOJ 2435][NOI 2011]道路修建
- 【dfs】【NOI 2011】【bzoj 2435】道路修建
- bzoj 2435: [Noi2011]道路修建 乱搞/水题
- bzoj 2435: [Noi2011]道路修建 (dfs)
- 【bzoj 2435】[Noi2011]道路修建(dfs)
- 【BZOJ 2435】【NOI 2011】道路修建【水题】
- ios 从一个app中打开另外一个app
- 典型的一个类对另一个类对象声明,数据交换的实例
- hdu 2084
- 李红霞作业第二章26题
- leetCode_3Sum
- BZOJ 3995 Sdoi2015 道路修建 线段树
- 线性代数导论19——行列式公式和代数余子式
- FJNU摸底赛_acdream1686(数学)
- HDOJ 题目4372 Count the Buildings(斯特林第一类数)
- matlab和C/C++混合编程--Mex
- 线性代数导论20——克莱姆法则、逆矩阵、体积
- 冒泡排序
- leetcode 第136题 Single Number
- 二进制转十进制