题意:给出n,m。n代表村庄的个数(村庄编号1~n),接下来进行m次操作。每次操作给出l,r,w,给[l,r]内所有村庄两两连边,每连一条边的代价是w。进行m次操作后,可能仍然存在不所有村庄不连通的情况,或者所有村庄都连通了。若所有村庄实现连通,现在让你删除尽可能多权重的边,使得删除这些边后所有村庄均保持直接或间接连通,输出被删除边的总权重,否则输出一行错误提示。
思路:线段树上贪心。对所有操作按边的权重降序排列,然后依次给线段树的区间赋新值(更小的值),这样总能保证线段树中的点是一直变小的。
code:
#include <bits/stdc++.h>
#define int long long
using namespace std ;
const int N = 1e5+10 ;
const int Initialval = 1e12 ;
struct Node{
int l , r , sum , lazy ;
};
struct Pair{
int l , r , w ;
bool operator < (Pair no1) const {
if(w != no1.w) return w > no1.w ;
else return false ;
}
};
Node tr[N*4] ;
Pair Edge[N];
int T ;
int n , m ;
void init()
{
for(int i = 0 ; i <= 4*n + 10 ; i++) tr[i] = {0,0,0,0};
}
void push_up(int u)
{
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum ;
}
void push_down(int u)
{
if(tr[u].lazy)
{
tr[u << 1].sum = (tr[u << 1].r - tr[u << 1].l + 1) * tr[u].lazy ;
tr[u << 1].lazy = tr[u].lazy ;
tr[u << 1 | 1].sum = (tr[u << 1 | 1].r - tr[u << 1 | 1].l + 1) * tr[u].lazy ;
tr[u << 1 | 1].lazy = tr[u].lazy ;
tr[u].lazy = 0 ;
}
}
void buildtr(int u , int l , int r)
{
tr[u] = {l , r , 0 , 0};
if(l == r) {
tr[u].sum = Initialval ;
}else{
int mid = (l + r) >> 1 ;
buildtr(u << 1 , l , mid) ;
buildtr(u << 1 | 1 , mid + 1 , r) ;
push_up(u);
}
}
void update(int u , int L , int R , int val)
{
if(L <= tr[u].l && tr[u].r <= R)
{
tr[u].sum = (tr[u].r - tr[u].l + 1) * val ;
tr[u].lazy = val ;
}else{
int mid = (tr[u].l + tr[u].r) >> 1 ;
push_down(u);
if(mid >= L) update(u << 1 , L , R , val) ;
if(mid + 1 <= R) update(u << 1 | 1 , L , R , val) ;
push_up(u);
}
}
int query(int u , int L , int R)
{
if(L <= tr[u].l && tr[u].r <= R)return tr[u].sum ;
else {
int mid = (tr[u].l + tr[u].r) >> 1 ;
push_down(u) ;
int ans = 0 ;
if(mid >= L) ans += query(u << 1 , L , R);
if(mid + 1 <= R) ans += query(u << 1 | 1 , L , R) ;
return ans ;
}
}
signed main()
{
//freopen("in","r",stdin);
scanf("%lld",&T) ;
for(int t = 1 ; t <= T ; t++)
{
scanf("%lld%lld",&n,&m);
init();
buildtr(1,1,n);
int IniSum = 0 ;
int Sum;
for(int i = 1 ; i <= m ; i++)
{
scanf("%lld%lld%lld",&Edge[i].l,&Edge[i].r,&Edge[i].w);
}
sort(Edge + 1, Edge + 1 + m) ;
for(int i = 1 ; i <= m ; i++)
{
int l , r , w ;
l = Edge[i].l , r = Edge[i].r , w = Edge[i].w ;
IniSum = IniSum + w * (r - l + 1) * (r - l) / 2 ;
update(1 , l , r - 1 , w);
}
printf("Case #%lld: ",t);
Sum = query(1,1,n-1);
if(Sum >= Initialval) printf("Gotta prepare a lesson\n");
else printf("%lld\n",IniSum - Sum);
}
return 0 ;
}