2017 多校联合训练 9 题解
Problem 1001
Problem 1002
考虑把每个询问拆分成2个单独的询问。
拆分后的询问为(s, t, x)。
也就是询问从s到t的最短路上所有权值小于等于x的点的权值总和。
我们把(s, t, a, b)拆成(s, t, a - 1) 和(s, t, b)。
那么第二个询问减去第一个询问的答案就是原来这个询问的答案。
我们把这2m个询问离线,以x为关键字升序排序。
这棵树的初始状态:所有点的权值都为0。
然后依次处理每个询问,先看有哪些点的权值小于等于当前询问的x值。
我们要保证当前所有满足条件的点都已经被更新到树上,如果还没更新就需要更新。
已经更新的不需要更新。
同时那些不满条件的点不在树上。
这个过程用双指针维护即可(但比赛的时候我为了省时间直接写了二分)
这样更新的总次数为n。
更新和查询用树链剖分维护就可以了。
时间复杂度$O(nlog^{2}(n) + mlogm + mlogn)$ (我的程序的复杂度)
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define lson i << 1, L, mid #define rson i << 1 | 1, mid + 1, R typedef long long LL; const int N = 1e5 + 10; struct query_node{ int x, y; LL a, b; } q[N]; struct query_Node{ int x, y; LL val; int id; LL ans; friend bool operator < (const query_Node &a, const query_Node &b){ return a.val < b.val; } } qu[N << 1]; struct Val{ int id; LL val; friend bool operator < (const Val &a, const Val &b){ return a.val < b.val; } } num[N]; vector <int> v[N]; int son[N], father[N], sz[N], deep[N], top[N], f[N], fp[N]; int n, m, cnt, tot, upnow; LL a[N], ret[N], Num[N], sum[N << 2]; bool cmp(const query_Node &a, const query_Node &b){ if (a.id != b.id) return a.id < b.id; else return a.val < b.val; } void dfs1(int x, int fa, int dep){ deep[x] = dep; father[x] = fa; son[x] = 0; sz[x] = 1; for (auto u : v[x]){ if (u == fa) continue; dfs1(u, x, dep + 1); sz[x] += sz[u]; if (sz[son[x]] < sz[u]) son[x] = u; } } void dfs2(int x, int tp){ top[x] = tp; f[x] = ++tot; fp[f[x]] = x; if (son[x]) dfs2(son[x], tp); for (auto u : v[x]){ if (u == father[x] || u == son[x]) continue; dfs2(u, u); } } inline void pushup(int i){ sum[i] = sum[i << 1] + sum[i << 1 | 1]; } void update(int i, int L, int R, int pos, LL val){ if (L == R && L == pos){ sum[i] = val; return ; } int mid = (L + R) >> 1; if (pos <= mid) update(lson, pos, val); if (pos > mid) update(rson, pos, val); pushup(i); } LL query_sum(int i, int L, int R, int l, int r){ if (L == l && R == r) return sum[i]; int mid = (L + R) >> 1; if (r <= mid) return query_sum(lson, l, r); else if (l > mid) return query_sum(rson, l, r); else return query_sum(lson, l, mid) + query_sum(rson, mid + 1, r); } LL find_sum(int x, int y){ int f1 = top[x], f2 = top[y]; LL ret = 0; for (; f1 != f2; ){ if (deep[f1] < deep[f2]) swap(f1, f2), swap(x, y); ret += query_sum(1, 1, n, f[f1], f[x]); x = father[f1], f1 = top[x]; } if (x == y) return ret + query_sum(1, 1, n, f[x], f[y]); if (deep[x] > deep[y]) swap(x, y); return ret + query_sum(1, 1, n, f[x], f[y]); } int main(){ while (~scanf("%d%d", &n, &m)){ rep(i, 1, n) scanf("%lld", a + i); rep(i, 0, n + 1) v[i].clear(); rep(i, 2, n){ int x, y; scanf("%d%d", &x, &y); v[x].push_back(y); v[y].push_back(x); } cnt = 0; rep(i, 1, m){ scanf("%d%d%lld%lld", &q[i].x, &q[i].y, &q[i].a, &q[i].b); ++cnt; qu[cnt].x = q[i].x; qu[cnt].y = q[i].y; qu[cnt].val = q[i].a - 1LL; qu[cnt].id = i; ++cnt; qu[cnt].x = q[i].x; qu[cnt].y = q[i].y; qu[cnt].val = q[i].b; qu[cnt].id = i; } sort(qu + 1, qu + cnt + 1); tot = 0; dfs1(1, 0, 0); dfs2(1, 1); rep(i, 1, n) num[i].val = a[i], num[i].id = i; sort(num + 1, num + n + 1); rep(i, 1, n) Num[i] = num[i].val; memset(sum, 0, sizeof sum); upnow = 0; rep(i, 1, cnt){ int pos = upper_bound(Num + 1, Num + n + 1, qu[i].val) - Num - 1; rep(j, upnow + 1, pos){ update(1, 1, n, f[num[j].id], num[j].val); } qu[i].ans = find_sum(qu[i].x, qu[i].y); upnow = pos; } sort(qu + 1, qu + cnt + 1, cmp); rep(i, 1, m) ret[i] = qu[i * 2].ans - qu[i * 2 - 1].ans; rep(i, 1, m - 1) printf("%lld ", ret[i]); printf("%lld\n", ret[m]); } return 0; }
Problem 1003
Problem 1004
Problem 1005
这道题我知道的有两种做法。
一个是缩点为DAG,则如果在拓扑序中出现了有两个及以上入度为0的点则不合法。
另一种是用bitset优化Floyd。
因为边数只有6000,所以不会TLE。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) const int N = 1e3 + 10; int n, m; bitset <N> f[N]; bool fl; int T; int main(){ scanf("%d", &T); while (T--){ scanf("%d%d", &n, &m); rep(i, 0, n + 1) f[i].reset(); rep(i, 1, m){ int x, y; scanf("%d%d", &x, &y); f[x][y] = 1; } rep(i, 1, n) rep(j, 1, n) if (f[j][i]) f[j] |= f[i]; fl = true; rep(i, 1, n - 1){ rep(j, i + 1, n){ if (!(f[i][j] || f[j][i])){ fl = false; break; } } if (!fl) break; } puts(fl ? "I love you my love and our love save us!" : "Light my fire!"); } return 0; }
Problem 1006
Problem 1007
Problem 1010
比赛时居然这题会卡这么长时间
一开始以为之前有类似的题 直接模拟就行
后来发现这题数据范围比之前那题大
因此需要用dp进行转移
另外 这题细节较多 需要注意
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cstring> 7 #include<string> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #include<queue> 12 using namespace std; 13 bool matchTmp(char *str, char *pattern){ 14 if(*str=='\0' && *pattern=='\0') return true; 15 if(*str!='\0' && *pattern=='\0') return false; 16 if(*(pattern+1)=='*'){ 17 if(*pattern==*str || (*pattern=='.'&&*str!='\0')) 18 { 19 bool b1= matchTmp(str+1,pattern+2); 20 bool b2= matchTmp(str,pattern+2); 21 if (b1||b2) return true; 22 pattern[0]=str[0]; 23 return matchTmp(str+1,pattern); 24 25 //return matchTmp(str+1,pattern+2) 26 //|| matchTmp(str+1,pattern) 27 //|| matchTmp(str,pattern+2); 28 } 29 else return matchTmp(str,pattern+2); 30 } 31 if(*str==*pattern || (*pattern=='.'&&*str!='\0')) 32 return matchTmp(str+1,pattern+1); 33 return false; 34 } 35 char s1[2510],s2[2510]; 36 pair<char,int> pipei[2510]; 37 bool fg[2510]; 38 int dp[2510][2]; 39 int main() 40 { 41 int _; 42 scanf("%d",&_); 43 while (_--) 44 { 45 scanf("%s",s1); 46 scanf("%s",s2); 47 int len1=strlen(s1),len2=strlen(s2); 48 int pos=0,cnt=0; 49 while (pos<len2) 50 { 51 if (pos+2<len2&&s2[pos]>='a'&&s2[pos]<='z'&&s2[pos+1]=='*') 52 { 53 //pipei[++cnt]={s2[pos],1}; 54 char c=s2[pos]; 55 pos+=2; 56 int tot=0,tt=0; 57 while (pos<len2&&(s2[pos]==c||s2[pos]=='*')) 58 { 59 pos++; 60 tot++; 61 if (s2[pos]=='*') tt++; 62 } 63 pipei[++cnt]={c,tot-tt*2}; 64 fg[cnt]=0; 65 } 66 else if (pos+1<len2&&s2[pos+1]=='*') 67 { 68 pipei[++cnt]={s2[pos],0}; 69 fg[cnt]=0; 70 pos+=2; 71 } 72 else if (s2[pos]>='a'&&s2[pos]<='z') 73 { 74 char c=s2[pos]; 75 int tot=0,tt=0; 76 bool nd=false; 77 while (pos<len2&&(s2[pos]==c||s2[pos]=='*')) 78 { 79 pos++; 80 tot++; 81 if (s2[pos]=='*') tt++,nd=true; 82 } 83 pipei[++cnt]={c,tot-tt*2}; 84 fg[cnt]=1; 85 if (nd) fg[cnt]=0; 86 } 87 else 88 { 89 pos++; 90 pipei[++cnt]={'.',1}; 91 fg[cnt]=1; 92 } 93 } 94 bool can=true; 95 int i,j; 96 //int mi=0,ma=0; 97 for (i=1;i<=cnt;i++) 98 { 99 dp[i][0]=999899; 100 dp[i][1]=0; 101 } 102 for (i=1;i<=cnt;i++) 103 { 104 bool used=false; 105 for (j=dp[i-1][0];j<=dp[i-1][1];j++) 106 { 107 if (fg[i]) 108 { 109 //cout<<i<<" "<<j<<endl; 110 int pos=j; 111 char c=pipei[i].first; 112 if (c=='.') c=s1[pos]; 113 int tt=0; 114 //if (i==6) cout<<s1[j]<<endl; 115 //if (i==4&&j==22) cout<<pos<<" "<<s1[pos]<<endl; 116 while (pos<len1&&s1[pos]==c) 117 { 118 pos++; 119 tt++; 120 if (tt==pipei[i].second) break; 121 } 122 if (tt==pipei[i].second) 123 { 124 used=true; 125 dp[i][0]=min(dp[i][0],pos); 126 dp[i][1]=max(dp[i][1],pos); 127 //cout<<i<<" "<<j<<" "<<dp[i][0]<<" "<<dp[i][1]<<endl; 128 } 129 } 130 else 131 { 132 char c=pipei[i].first; 133 bool fg2=false; 134 int pos=j; 135 if (c=='.') 136 { 137 c=s1[pos]; 138 fg2=true; 139 } 140 int tt=0; 141 if (pipei[i].second==0) 142 { 143 used=true; 144 //cout<<i<<" "<<used<<endl; 145 dp[i][0]=min(dp[i][0],pos); 146 dp[i][1]=max(dp[i][1],pos); 147 148 } 149 while (pos<len1&&s1[pos]==c) 150 { 151 //pos++; 152 //tt++; 153 //cout<<tt<<" "<<pipei[i].second<<endl; 154 pos++; 155 tt++; 156 if (tt>=pipei[i].second) 157 { 158 used=true; 159 dp[i][0]=min(dp[i][0],pos); 160 dp[i][1]=max(dp[i][1],pos); 161 //cout<<i<<" "<<dp[i][0]<<" "<<dp[i][1]<<endl; 162 //cout<<"hhhhhhh"<<" "<<pos<<endl; 163 } 164 //pos++; 165 //tt++; 166 167 } 168 } 169 } 170 if (!used||dp[i][0]>dp[i][1]) 171 { 172 173 //cout<<i<<" "<<used<<endl; 174 can=false; 175 break; 176 } 177 //cout<<i<<" "<<dp[i][0]<<" "<<dp[i][1]<<" "<<s1[dp[i][0]]<<" "<<s1[dp[i][1]]<<endl; 178 } 179 // for (i=1;i<=cnt;i++) 180 // printf("%c %d %d\n",pipei[i].first,pipei[i].second,fg[i]); 181 /*for (i=1;i<=cnt;i++) 182 { 183 if (fg[i]) 184 { 185 char c=pipei[i].first; 186 if (c=='.') c=s1[pos]; 187 int tt=0; 188 while (pos<len1&&s1[pos]==c) 189 { 190 pos++; 191 tt++; 192 if (tt==pipei[i].second) break; 193 } 194 if (tt<pipei[i].second) 195 { 196 can=false; 197 //cout<<pos<<" "<<tt<<" "<<i<<" "<<"hhhhhhh"<<endl; 198 break; 199 } 200 201 } 202 else 203 { 204 char c=pipei[i].first; 205 bool fg2=false; 206 if (c=='.') 207 { 208 c=s1[pos]; 209 fg2=true; 210 } 211 int tt=0; 212 while (pos<len1&&s1[pos]==c) 213 { 214 pos++; 215 tt++; 216 } 217 if (tt<pipei[i].second) 218 { 219 //cout<<"hhhhhh"<<endl; 220 can=false; 221 //cout<<tt<<" "<<i<<" "<<"hhhhhhhhhh"<<endl; 222 break; 223 } 224 if (i<cnt&&fg2&&pipei[i+1].first==c) 225 { 226 if (fg[i+1]) 227 { 228 if (tt<pipei[i+1].second) 229 { 230 can=false; 231 break; 232 } 233 pos-=pipei[i+1].second; 234 } else 235 pos--; 236 } 237 } 238 }*/ 239 //cout<<dp[cnt][0]<<" "<<len1<<endl; 240 puts(can&&dp[cnt][0]<=dp[cnt][1]&&dp[cnt][1]>=len1?"yes":"no"); 241 } 242 return 0; 243 }