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连通,输出不行。
   
posted @ 2021-09-23 19:51  lipu123  阅读(74)  评论(0)    收藏  举报