您的位置:首页 > 其它

bzoj1202(第一篇博客,大家快来捧场吧)

2018-01-25 23:05 190 查看
1、一般碰到连续区间的题,可以用并查集,把他的祖先记为能到达的最长区间的端点(通常为右端点);

2、求两个区间的差不一定要硬生生地求,如果有一种比较优的算法能记录这两个区间加上另一个重复的区间,那么减的时候可以抵消掉重复区间,对答案没影响。

3、该题中,f[x]代表以x+1为左端点所在最长区间最右端点,l[x]代表以x+1为左端点所在最长区间的权值(注意是x+1)。记录时做这两步:

①若祖先相同,判断v是否等于l[b]-l[a-1],这很好理解;

②若不同则合并。l[f[a-1]]=l[b]+v-l[[a-1]],f[f[a-1]]=f[b].

这里有一个难点,如果f[a-1]比f[b]大这个式子还成立吗?答案是成立的。因为这时候l[f[a-1]]等于f[b]+1到f[a-1]的值的相反数。当再次查他们的时候,由于fb在左边,所以计算的是l[fb]-l[f[a-1]],这对答案真的没影响!

再深入思考,为什么特例对了呢?我个人认为,l【x】的意义不一定要以左右来看,可以是时间先后,x是第一个点,在这个区间f【x】为他最后到的那个点,往左走当然就是往右走的相反数了!可能没说清,但大家可以感性体会一下这个意思。

下面附AC代码:

,#include<bits/stdc++.h>
using namespace std;
#define maxn 105
int w,n,m,f[maxn],l[maxn];
void find(int x){
if(x==f[x])return ;
find(f[x]);
l[x]+=l[f[x]];
f[x]=f[f[x]];}
int main(){
scanf("%d",&w);
while(w--){
int j=0;
scanf("%d%d",&n,&m);
for(int i=0;i<maxn;i++){l[i]=0;f[i]=i;}
for(int i=1;i<=m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);a--;
find(a);find(b);
if(f[a]==f[b]){if(l[a]-l[b]!=c)j=1;continue;}
l[f[a]]=l[b]+c-l[a];f[f[a]]=f[b];}
if(j)printf("false\n");else printf("true\n");}
return 0;}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息