D Edge of Taixuan
题目描述
给定n个点, m个区间, 每个区间有l, r, w, 代表会对l到r内的所有
点对连一条长度为w的边,就是说如果是[1,3],则有边[1,2],[1,3],[2,3]
问最多能去掉边和多长,使得剩下的点都和1号点直接或者间接相连。
如果有点,不能和1连通,输出不行。
题目解析
对于每一次操作会使用(r-l+1)*(r-l)/2*w的长度(所有点*能组成的对的点)/2是去除重复的,*w是每对的长度
可以算出总使用的长度,然后减去使所有点相连的最短长度,剩下的就是可去除的最长的长度。
将点上的值当成与后面点相连的边的长度。
将所有操作按照w从大到小排序,然后按照顺序对l到r-1修改成新值,因为是区间赋值,然后按照从大到小排序,越往后越小就行。
最后判断时,若所有点相连,代表1-(n-1)非0,后覆盖的值会越来越小,保证每个点向连用的边是最短的
Code
#include<iostream> #include<algorithm> using namespace std; const int maxn=1e6+100; typedef long long ll; struct node{ int l,r; ll mi; ll lazy; ll sum; }t[maxn]; struct Node{ ll l,r,w; bool friend operator<(Node a,Node b){ return a.w>b.w; } }save[maxn]; void push_up(int p){ t[p].mi=min(t[2*p].mi,t[2*p+1].mi); t[p].sum=t[2*p].sum+t[2*p+1].sum; } void build(int p,int l,int r){ t[p].l=l; t[p].r=r; t[p].mi=0; t[p].sum=0; t[p].lazy=0; if(t[p].l==t[p].r){ return ; } int mid=(t[p].l+t[p].r)/2; build(2*p,l,mid); build(2*p+1,mid+1,r); push_up(p); } void push_down(int p){ if(!t[p].lazy) return ; t[2*p].lazy=t[p].lazy; t[2*p+1].lazy=t[p].lazy; t[2*p].mi=t[p].lazy; t[2*p+1].mi=t[p].lazy; t[2*p].sum=(t[2*p].r-t[2*p].l+1)*t[p].lazy; t[2*p+1].sum=(t[2*p+1].r-t[2*p+1].l+1)*t[p].lazy; t[p].lazy=0; } void update(int p,int l,int r,ll x){ if(t[p].l>=l&&t[p].r<=r){ t[p].sum=1ll*(t[p].r-t[p].l+1)*x; t[p].lazy=x; t[p].mi=x; return ; } push_down(p); int mid=(t[p].l+t[p].r)/2; if(l<=mid){ update(2*p,l,r,x); } if(r>mid){ update(2*p+1,l,r,x); } push_up(p); } ll query(int p,int l,int r){ if(t[p].l>=l&&t[p].r<=r){ return t[p].sum; } int mid=(t[p].l+t[p].r)/2; push_down(p); ll ans=0; if(l<=mid){ ans+=query(2*p,l,r); } if(r>mid){ ans+=query(2*p+1,l,r); } push_up(p); return ans; } int main(){ int _; cin>>_; int kase=0; while(_--){ int n,m; cin>>n>>m; build(1,1,n-1); ll ans=0; for(int i=1;i<=m;i++){ scanf("%lld%lld%lld",&save[i].l,&save[i].r,&save[i].w); ll len=(save[i].r-save[i].l+1); ans+=(len*(len-1)/2)*save[i].w; } //cout<<ans<<endl; sort(save+1,save+m+1); for(int i=1;i<=m;i++){ update(1,save[i].l,save[i].r-1,save[i].w); } printf("Case #%d: ",++kase); //cout<<t[1].mi<<endl; if(t[1].mi==0){ cout<<"Gotta prepare a lesson"<<"\n"; } else{ cout<<ans-t[1].sum<<"\n"; } } }
给定n个点, m个区间, 每个区间有l, r, w, 代表会对l到r内的所有
|
|
点对连一条长度为w的边。
|
|
问最多能去掉边和多长,使得剩下的点都和1号点直接或者间接相连。
|
|
如果有点,不能和1连通,输出不行。
|
|