ICPC第一场网络赛补题 D
题目链接link.
好后悔场上最后二十分钟才看这个题呜呜呜
题意:n个点,m次操作,每次操作给一个 l l l 给一个 r r r 一个 w w w, 给区间 [ l , r ] [l,r] [l,r] 内所有的点对之间都连一条权值为 w w w 的边,问你m次操作后,如果有点和1没有连起来,则输出“Gotta prepare a lesson”,否则输出,能删除的边的最大权值,使得这个图还是连通图。
这题,后期都过烂了。可惜因为我之前K题那个傻逼模拟犯了一些傻逼错误一直wa,就没心思开新的题。最后连过两题发现开的题都过了,没题目做了,再一看榜我超这题怎么过了这么多。
具体的做法,我们可以反向考虑。算出这个联通图的最小的权值和。先说一下我的大常数必须要带快读的做法。做法就是用线段树维护区间min,我们可以知道,最后删完边之后最小连通图的分布一定可以满足 1连2,2连3, 3连4…这样子。所以我们只需要维护一颗大小为 n − 1 n-1 n−1 的线段树。每次给的操作,都让对应的线段与操作给出的w取最小值就好。但是这样做不好维护sum,只能最后query(n-1)次再求和了。问题就在这里,这样查询n-1次可能常数就比较大了…不过加加快读还是可以过去的。
然后捏,还有一种优化的做法,就是我们不维护min了,我们之间修改区间值并且维护sum。首先,我们可以考虑离线的做,把m次操作按照w的值从大到小排序。然后先区间修改w大的。这样可以直接修改,因为你肯定会越改越小嘛,对吧。而且这样就很好维护sum了,常数会小一些。
AC代码:
#include<iostream>
#include<cstdio>
using namespace std;
const long long inf=99999999;
long long lread()
{
long long x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9')
x=x*10+ch-'0',ch=getchar();
return x*f;
}
struct QwQ
{
long long l,r;
long long value;
long long lazy_tag=inf;
}tree[4*100010];
void build(long long x,long long l,long long r)
{
tree[x].l=l;
tree[x].r=r;
tree[x].lazy_tag=inf;
if(l==r)
{
tree[x].value=inf;
return ;
}
long long mid=(l+r)/2;
build(x*2,l,mid);
build(x*2+1,mid+1,r);
tree[x].value=min(tree[x*2].value,tree[x*2+1].value);
}
void update(long long x,long long w)
{
tree[x].value= min(tree[x].value,w);
tree[x].lazy_tag= min(tree[x].lazy_tag,w);
//tree[x].lazy_tag=w;
return ;
}
void push_down(long long x)
{
update(x*2,tree[x].lazy_tag);
update(x*2+1,tree[x].lazy_tag);
tree[x].lazy_tag=inf;
}
void push_up(long long x)
{
tree[x].value=min(tree[x*2].value ,tree[x*2+1].value);
}
void change(long long x,long long l,long long r,long long w)
{
if(tree[x].l==l&&tree[x].r==r)
{
update(x,w);
return ;
}
if(tree[x].lazy_tag!=inf) push_down(x);
long long mid=(tree[x].l+tree[x].r)/2;
if(r<=mid) change(x*2,l,r,w);
else if(l>=mid+1) change(x*2+1,l,r,w);
else
{
change(x*2,l,mid,w);
change(x*2+1,mid+1,r,w);
}
push_up(x);
}
long long query(long long x,long long l,long long r)
{
if(tree[x].l==l&&tree[x].r==r)
{
return tree[x].value;
}
if(tree[x].lazy_tag!=0) push_down(x);
long long mid=(tree[x].l+tree[x].r)/2;
if(r<=mid)
{
return query(x*2,l,r);
}
else if(l>=mid+1)
{
return query(x*2+1,l,r);
}
else
{
return min(query(x*2,l,mid),query(x*2+1,mid+1,r));
}
}
int main( )
{
int t;
scanf("%d",&t);
for(int haha=1;haha<=t;haha++)
{
long long n,m;
//scanf("%lld%lld",&n,&m);
n=lread();
m=lread();
long long sum=0;
build(1,1,n-1);
//a[k]代表[k,k+1)这一段的值
for(int xixi=1;xixi<=m;xixi++)
{
long long l,r,w;
//scanf("%lld%lld%lld",&l,&r,&w);
l=lread();r=lread();w=lread();
sum=sum+ (r-l+1)*(r-l)*w/2;
change(1,l,r-1,w);
}
long long cnt=0;
int flag=0;
for(long long xixi=1;xixi<=n-1;xixi++)
{
long long wuwu=query(1,xixi,xixi);
cnt=cnt+ wuwu;
if(wuwu == inf)
flag=1;
}
long long ans=sum-cnt;
printf("Case #%d: ",haha);
if(flag==1) printf("Gotta prepare a lesson");
else printf("%lld",ans);
if(haha!=t) printf("\n");
}
return 0;
}