[HNOI2005]狡猾的商人
题意:
有一个数列,告诉你m组区间和,问区间和中是否有冲突(即错误)
比如2 4 3 4 7 5 (你不知道这个数列,但都是正整数)
告诉你:
2 ~ 4 = 11
1 ~ 3 = 9
1 ~ 2 = 11
这就不合法,虽然数列未知,但1~2的区间和比1~3的还小,这显然是不可能的
题解:
首先它告诉我们的是区间和,那首先就要想到前缀和。
于是我们设dis[i]表示1~i的区间和,
那么题目实际上就是告诉你这样一组等式:
dis[i] - dis[j] = k[t]
dis[k] - dis[l] = k[t+1]
.......
是不是很眼熟?
没错就是差分约束
但由于这里是等号,而不是大于小于,
因此我们的目标不再是找最短路
因为最短路是在尽量不等式
而这里是等式
所以我们的目标应该是判断到达一个点的所有路径是否相等
一开始我想的是跑两遍spfa,一遍找最短路,一遍找最长路,
再判断最短路和最长路是否相等,
后来A完之后看大佬的,才发现其实直接在找最短路的时候,
每次访问到一个点就判断是否与之前找到的路径长度相同就可以了
如果有至少一个不同,那就是不合法
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define R register int 4 #define inf -2139062144 5 #define AC 150 6 #define ACway 5000 7 int T,n,m; 8 int Head[AC],date[ACway],Next[ACway],length[ACway],tot; 9 int q[ACway],head,tail; 10 int min_dis[AC],max_dis[AC]; 11 bool vis[AC]; 12 /*猜一个结论, 13 对于dis[i] - dis[j] = w[k], 14 连 j ---> i : w[k]的边, 15 如果合法,那么原本的dis[i]将无法被更新???? 16 也就是说,通过0号节点走任意路径到达的任意节点的权值和是一定的, 17 简单来说就是最短路 == 最长路 18 or 满足两个差分约数条件? 19 即dis[i] - dis[j] <= w[k] 20 + dis[j] - dis[i] <= w[k](dis[i] - dis[j] >= w[k]) 21 算了还是最短路 == 最长路吧,,,不然不知道怎么判断*/ 22 inline int read() 23 { 24 int x=0;char c=getchar();bool z=false; 25 while(c > '9' || c < '0') {if(c == '-') z=true; c=getchar();} 26 while(c >= '0' && c <= '9') x=x * 10 + c - '0' , c=getchar(); 27 if(!z) return x; 28 else return -x; 29 } 30 31 inline void add(int f,int w,int S) 32 { 33 //printf("%d ---> %d : %d\n",f,w,S); 34 date[++tot]=w,Next[tot]=Head[f],length[tot]=S,Head[f]=tot; 35 } 36 37 void pre() 38 { 39 int a,b,c; 40 n=read(),m=read(); 41 tot=0; 42 memset(Head,-1,sizeof(Head));//因为有0号几点的参与,所以是置为-1,而不是0 43 for(R i=1;i<=m;i++) 44 { 45 a=read(),b=read(),c=read();//因为是sum[b] - sum[a-1] 46 add(a-1,b,c);//类似前缀和的东西 47 } 48 memset(max_dis,128,sizeof(max_dis)); 49 memset(min_dis,127,sizeof(min_dis)); 50 } 51 52 #define dis min_dis 53 void spfa(int b)//search for the shortest road 54 { 55 int x,now; 56 memset(dis,127,sizeof(dis)); 57 head=tail=0;//先把0放入 58 q[++tail]=b , dis[b]=0;//因为直接把tail赋为1的话,q[1]可能不为0 59 memset(vis,0,sizeof(vis)); 60 while(head < tail) 61 { 62 x=q[++head]; 63 for(R i=Head[x]; i!=-1 ;i=Next[i]) 64 { 65 now=date[i]; 66 if(dis[now] > dis[x] + length[i]) 67 { 68 dis[now] = dis[x] + length[i]; 69 if(!vis[now]) q[++tail]=now,vis[now]=true; 70 } 71 } 72 vis[x]=false; 73 } 74 } 75 #undef dis //仿佛发现神器。。。。 76 77 #define dis max_dis 78 void SPFA(int b)//search for the longest road 79 { 80 int x,now; 81 memset(dis,128,sizeof(dis)); 82 head=tail=0; 83 q[++tail]=b , dis[b]=0; 84 memset(vis,0,sizeof(vis)); 85 while(head < tail) 86 { 87 x=q[++head]; 88 for(R i=Head[x]; i!=-1 ;i=Next[i]) 89 { 90 now=date[i]; 91 if(dis[now] < dis[x] + length[i]) 92 { 93 dis[now] = dis[x] + length[i]; 94 if(!vis[now]) q[++tail]=now,vis[now]=true; 95 } 96 } 97 vis[x]=false; 98 } 99 } 100 #undef dis 101 102 void solve() 103 { 104 bool flag; 105 scanf("%d",&T); 106 for(R i=1;i<=T;i++) 107 { 108 pre();//要遍历完每一个联通块,不然就会有些部分访问不到 109 flag=false; 110 for(R j=0;j<=n;j++) 111 { 112 if(max_dis[j] == inf) 113 { 114 spfa(j); 115 SPFA(j); 116 } 117 for(R k=1;k<=n;k++) 118 { 119 if(max_dis[k] == inf) continue; 120 if(max_dis[k] != min_dis[k]) 121 { 122 flag=true; 123 printf("false\n"); 124 break; 125 } 126 } 127 if(flag) break; 128 } 129 if(!flag) printf("true\n"); 130 } 131 } 132 133 int main() 134 { 135 // freopen("in.in","r",stdin); 136 solve(); 137 // fclose(stdin); 138 return 0; 139 }