Wannafly挑战赛13
A题模拟
B题等价于有n^2 -1个白球 1个黑球 摸出来m个摸到黑球的概率 组合数学搞搞
C题我猜了下,就是1到n行 每行加0,1,2,...n-1 每列加1,n+1,2n+1.....n^2-n+1是一种可行解 然后两边全排列的情况也行,然后交换行列的位置也行,所以是2*(p!)^2
D题切一个蛋糕肯定是均匀切划算,因为不均匀切这一刀就会贡献质量差,然后就是找到最大的蛋糕,对它多切一刀看行不行模拟。
E题先把线段按右端点排序,能与当前线段产生异或最大的会排在前面,我们就从左到右处理,首先对于当前处理的线段l,r先二分出之前线段的r在当前线段的[l,r]之间的范围,然后就是查询这个范围的线段的l+r,与l-r ,画一画就知道了。
#include <iostream> #include <stdio.h> #include <cstring> #include <algorithm> #include <vector> #include <map> using namespace std; const int maxn = 2e5+9; struct line{ int l,r; bool operator <(line a)const{ return r<a.r; } }l[maxn]; const int inf = 0x3f3f3f3f; struct Node{ int p[2]; }node[maxn<<2]; void build(int l,int r,int root){ if(l==r){ node[root].p[0] = inf; node[root].p[1] = -inf; return ; } int mid=l+r>>1; build(l,mid,root<<1); build(mid+1,r,root<<1|1); } void pushup(int root){ node[root].p[0] =min(node[root<<1].p[0],node[root<<1|1].p[0]); node[root].p[1] =max(node[root<<1].p[1],node[root<<1|1].p[1]); } void update(int l,int r,int root,int pos,int p0,int p1){ if(l==r){ node[root].p[0] = p0; node[root].p[1] = p1; return; } int mid=l+r>>1; if(pos<=mid) update(l, mid, root<<1, pos, p0, p1); else update(mid+1, r, root<<1|1, pos, p0, p1); pushup(root); } int ql,qr; int pp0,pp1; void query(int l,int r,int root){ if(ql<=l && r<=qr) { pp0 = min(pp0,node[root].p[0]); pp1 = max(pp1,node[root].p[1]); return ; } int mid=l+r>>1; if(qr<=mid) { query(l, mid, root<<1); }else if(ql>mid) { query(mid+1, r,root<<1|1); }else { query(l, mid, root<<1); query(mid+1, r, root<<1|1); } } int bs(int ll,int rr,int val){ int ans = rr; while (ll<=rr) { int mid=ll+rr>>1; if(l[mid].r>=val){ rr=mid-1; ans = mid; }else{ ll = mid+1; } } return ans; } int main(int argc, const char * argv[]) { int n; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d%d",&l[i].l,&l[i].r); } sort(l+1,l+1+n); build(1,n,1); int anss = 0; for(int i=1;i<=n;i++){ update(1, n, 1, i, l[i].l+l[i].r,l[i].l-l[i].r); qr = i; ql = bs(1,i,l[i].l); pp0 = inf; pp1 = -inf; query(1, n, 1); anss = max(anss,l[i].l+l[i].r-pp0); anss = max(anss,l[i].r-l[i].l+pp1); } printf("%d\n",anss); return 0; }
F题,主要思路就是通过对可爱值的分块,优化q^2的大暴力,首先我们可以在n+q的时间内处理Q个修改对n个点的影响,然后我们也有O(1)的算法解决已知u,v路径上被放了花,然后任意一点到这路径花的距离和,然后我门就可以把询问分块,分成q/N块,对于新来的询问,我们放进去询问中,如果询问是N的倍数,我们就重构之前所有的询问,每块重新维护的复杂度是n 然后一共有q/N块,重构的次数不会超过q/N次,反正就十分血腥暴力。
主要学到了把dfs改成了非递归的形式,还有树上差分的玩法(该点的真实值等于其所有子节点的差分数组和),好好写了一遍RMQ-LCA,log2打表的正确姿势,还有auto关键字玩lambda表达式,inplace_merge原地归并(暴力重构),还有lower_bound和upper_bound的手动实现和std玩法(感受到了前开后闭区间的优越性)。
#include <iostream> #include <stdio.h> #include <cstring> #include <algorithm> #include <vector> #include <map> using namespace std; typedef long long int ll; /* 1.实现RMQ-LCA */ const int maxn = 1e5+9; const int S = 800; const int N = maxn/S+5; const int K = 18; ll VAL[N][maxn]; struct query{ int u,v,x; }Q[maxn]; vector<int> vv[maxn]; int dep[maxn]; int ST_table[18][maxn<<1],first[maxn],dfsv[maxn],father[maxn]; int stcnt,dfscnt; int Log2[maxn<<1]; ll qz[maxn]; void dfs(int now,int fa){ ST_table[0][++stcnt] = now; first[now] = stcnt; dfsv[++dfscnt] = now; for(auto v:vv[now]) if(fa != v){ dep[v] = dep[now]+1; father[v] = now; dfs(v, now); ST_table[0][++stcnt] = now; } } inline int depmin(int u,int v){ return dep[u]<dep[v]?u:v; } void ST_init(){ for(int i=1;i<18;i++){ for(int j=1;j+(1<<(i-1))<=stcnt;j++){ ST_table[i][j] = depmin(ST_table[i-1][j],ST_table[i-1][j+(1<<(i-1))]); } } } inline int lca(int u,int v){ int posu = first[u]; int posv = first[v]; if(posu>posv) swap(posu,posv); int step = Log2[posv-posu+1]; return depmin(ST_table[step][posu],ST_table[step][posv-(1<<step)+1]); } inline ll cal(ll a,ll b){ if(a==0) a++; return qz[b]-qz[a-1]; } inline ll cal(int u,int v,int x){ int lcauv =lca(u,v); int lcauvx = lca(lcauv,x); if(dep[lcauvx]<dep[lcauv]){ ll dis1 = dep[x]+dep[lcauv]-2*dep[lcauvx]; ll dis2 = dep[x]+dep[u]-2*dep[lcauvx]; ll dis3 = dep[x]+dep[v]-2*dep[lcauvx]; return cal(dis1,dis2)+cal(dis1, dis3)-dis1; } int lcaux = lca(u,x); if(dep[lcaux]<=dep[lcauv]){ swap(u,v); lcaux = lca(u,x); } ll dis1 = dep[x]-dep[lcaux]; ll dis2 = dep[x]+dep[u]-2*dep[lcaux]; ll dis3 = dep[x]+dep[v]-2*dep[lcauv]; return cal(dis1,dis2)+cal(dis1, dis3)-dis1; } int P[maxn]; ll dp[maxn]; void build(query *Q,ll *val,int n){ for(int i=0;i<=n;i++){ val[i] = 0; P[i] = 0; dp[i] = 0; } for(int i=0;i<S;i++){ int u = Q[i].u,v = Q[i].v,lcauv=lca(u,v); P[u]++,P[v]++,P[lcauv]--,P[father[lcauv]]--; } for(int i=n;i>=1;i--){ int u = dfsv[i]; int v = father[u]; P[v]+=P[u]; dp[u]+=P[u]; dp[v]+=dp[u]; val[v]+=val[u]+dp[u]; } for(int i=1;i<=n;i++){ int u= dfsv[i]; val[u] = val[father[u]]+dp[1]-(dp[u]<<1); } } int allquery; int bigall; inline int lower(int st,int ed,int x){ int ret = ed; while (st<ed) { int mid= st+ed>>1; if(Q[mid].x>=x){ ret = mid; ed = mid; }else{ st = mid+1; } } return ret; } inline int upper(int st,int ed,int x){ int ret = ed; while (st<ed) { int mid= st+ed>>1; if(Q[mid].x>x){ ret = mid; ed = mid; }else{ st = mid+1; } } return ret; } int main(int argc, const char * argv[]) { for(int i=2;i<(maxn<<1);i++){ Log2[i] = Log2[i>>1]+1; } for(int i=0;i<maxn;i++){ qz[i] = 1ll*(i+1)*i/2; } int n,m; scanf("%d%d",&n,&m); for(int i=1;i<n;i++){ int u,v; scanf("%d%d",&u,&v); vv[u].push_back(v); vv[v].push_back(u); } dep[1] = 0; dfs(1,0); ST_init(); while (m--) { int ty,x,y,z; scanf("%d%d%d%d",&ty,&x,&y,&z); if(ty==1){ Q[allquery++] ={x,y,z}; if(allquery%S==0){ auto cmp = [](const query&A,const query&B){return A.x<B.x;}; sort(Q+bigall, Q+allquery, cmp); inplace_merge(Q, Q+bigall, Q+allquery, cmp); for(int i=0;i<(bigall=allquery)/S;i++){ build(Q+i*S, VAL[i], n); } } }else{ ll res= 0; for(int i=bigall;i<allquery;i++) if(Q[i].x<=y && Q[i].x>=x){ res+= cal(Q[i].u, Q[i].v, z); } int L = lower(0, bigall, x); //int L=lower_bound(Q,Q+bigall,x,[](query A,int x){return A.x<x;})-Q; //int R=upper_bound(Q,Q+bigall,y,[](int x,query A){return x<A.x;})-Q; int R = upper(0, bigall, y); if(L/S==R/S) { for(int i=L;i<R;i++){ res+= cal(Q[i].u, Q[i].v, z); } } else{ for(int i=L/S+1;i<R/S;i++) res+=VAL[i][z]; for(int i=L;i<L/S*S+S;i++) res+=cal(Q[i].u,Q[i].v,z); for(int i=R/S*S;i<R;i++) res+=cal(Q[i].u,Q[i].v,z); } printf("%lld\n",res); } } return 0; } /* 10 20 6 7 1 2 5 4 1 3 10 8 7 9 1 8 1 4 2 6 1 5 1 27280262 1 2 4 27245688 2 27234840 27290934 6 1 10 6 27227228 2 27313334 27321446 3 1 9 10 27258713 1 3 4 27249714 2 27270810 27309316 1 1 9 2 27254034 2 27292791 27302394 10 1 7 5 27319311 1 5 6 27301947 1 10 1 27318014 2 27247634 27320484 9 1 10 5 27299018 2 27240281 27286743 8 2 27296751 27319246 4 2 27309633 27314750 9 2 27257490 27301409 6 2 27235007 27294034 2 */