一道大暴力被人说做法雷同...真的是醉了
T1 树上路径最小值(min)
给一棵树,多次询问两点间路径上点权最小值
sol:树链剖分 倍增 平衡树(划掉)
瞎J2乱做都可以
然而太困了爆零
#include<bits/stdc++.h> using namespace std; inline int read() { int x = 0,f = 1;char ch = getchar(); for(;!isdigit(ch);ch = getchar())if(ch == '-') f = -f; for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0'; return x * f; } const int maxn = 1e5 + 777; int n; int first[maxn],to[maxn << 1],next[maxn << 1],cnt; int a[maxn],size[maxn],bl[maxn],fa[maxn],depth[maxn],dfn; int pos[maxn],reh[maxn]; inline void add(int u,int v) { to[++cnt] = v;next[cnt] = first[u];first[u] = cnt; } inline void ins(int u,int v){add(u,v);add(v,u);} inline void dfs1(int u) { size[u] = 1; for(int i=first[u];i;i=next[i]) { if(to[i] == fa[u])continue; fa[to[i]] = u;dfs1(to[i]);depth[to[i]] = depth[u] + 1;size[u] += size[to[i]]; } } inline void dfs2(int u,int col) { int k = 0;pos[u] = ++dfn;reh[pos[u]] = u;bl[u] = col; for(int i=first[u];i;i=next[i]) if(to[i] != fa[u] && size[to[i]] > size[k])k = to[i]; if(!k)return; dfs2(k,col); for(int i=first[u];i;i=next[i]) if(to[i] != fa[u] && k != to[i])dfs2(to[i],to[i]); } int seg[maxn << 2]; #define ls (x << 1) #define rs ((x << 1) | 1) inline void update(int x,int l,int r,int pos,int val) { if(l == r) { seg[x] = val; return; } int mid = (l + r) >> 1; if(pos <= mid)update(ls,l,mid,pos,val); else update(rs,mid + 1,r,pos,val); seg[x] = min(seg[ls],seg[rs]); } inline int query(int x,int l,int r,int L,int R) { if(L <= l && r <= R)return seg[x]; int mid = (l + r) >> 1,ans = 2147483233; if(L <= mid)ans = min(ans,query(ls,l,mid,L,R)); if(R > mid)ans = min(ans,query(rs,mid + 1,r,L,R)); return ans; } int main() { freopen("min.in","r",stdin); freopen("min.out","w",stdout); int q; for(int i=1;i<maxn * 4;i++)seg[i] = 2147483233; n = read();q = read(); for(int i=1;i<=n;i++)a[i] = read(); for(int i=2;i<=n;i++) { int u = read(),v = read(); ins(u,v); }dfs1(1);dfs2(1,1); for(int i=1;i<=n;i++)update(1,1,n,pos[i],a[i]); while(q--) { int u = read(),v = read();int ans = 2147483233; while(bl[u] != bl[v]) { if(depth[bl[u]] < depth[bl[v]])swap(u,v); ans = min(ans,query(1,1,n,pos[bl[u]],pos[u])); u = fa[bl[u]]; } if(pos[u] > pos[v])swap(u,v); ans = min(ans,query(1,1,n,pos[u],pos[v])); printf("%d ",ans); } }
#include<iostream> #include<cstring> #include<cstdio> #define MAXN 131072 using namespace std; inline int read() { int x=0,t=1,c; while(!isdigit(c=getchar()))if(c=='-')t=-1; while(isdigit(c))x=x*10+c-'0',c=getchar(); return x*t; } int n,q; int a[MAXN]; int first[MAXN],targ[MAXN<<1],nxt[MAXN<<1],cnte=1; int anc[MAXN][22],minv[MAXN][22],deep[MAXN]; void AddEdge(int u,int v) { targ[cnte]=v;nxt[cnte]=first[u];first[u]=cnte++;swap(u,v); targ[cnte]=v;nxt[cnte]=first[u];first[u]=cnte++; } void DFS(int x=1,int Fa=0) { anc[x][0]=Fa; minv[x][0]=min(a[x],a[Fa]); for(int i=1;i<20;i++) { anc[x][i]=anc[anc[x][i-1]][i-1]; minv[x][i]=min(minv[x][i-1],minv[anc[x][i-1]][i-1]); } for(int i=first[x];i;i=nxt[i]) { if(targ[i]!=Fa) { deep[targ[i]]=deep[x]+1; DFS(targ[i],x); } } } void Jump(int &x,int f,int &r) { r=min(r,minv[x][f]); x=anc[x][f]; } int LCA(int x,int y) { int ret=min(a[x],a[y]); if(deep[x]<deep[y])swap(x,y); for(int i=19;i>=0;i--) { if((1<<i)<=deep[x]-deep[y])Jump(x,i,ret); } for(int i=19;i>=0;i--)if(anc[x][i]!=anc[y][i])Jump(x,i,ret),Jump(y,i,ret); if(x!=y)Jump(x,0,ret),Jump(y,0,ret); //printf("%d %d ",x,y); return ret; } int main() { freopen("min.in","r",stdin); freopen("min.out","w",stdout); n=read(),q=read(); for(int i=1;i<=n;i++)a[i]=read(); for(int i=1;i<n;i++)AddEdge(read(),read()); deep[1]=1; DFS(); for(int i=0;i<q;i++) { printf("%d ",LCA(read(),read())); } } /* 7 7 1 2 3 4 5 6 7 1 2 2 4 3 2 4 6 5 6 6 7 1 7 2 6 3 5 1 2 3 4 5 6 4 7 */
T2 k大异或和
给一个数组a,求a中第k小的非空子序列异或和
n<=1e4
sol:记录一下当前的是第几大,具体可以通过一个桶前缀和来搞,然后upperbound
高二的几个小伙伴都是这么写的于是被D了
标算是桶排序。。。
无语
#include<bits/stdc++.h> using namespace std; inline int read() { int x = 0,f = 1;char ch = getchar(); for(;!isdigit(ch);ch = getchar())if(ch == '-') f = -f; for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0'; return x * f; } const int maxn = 1e4 + 10; int n,q,k; int a[maxn],s[maxn]; int sum[1049000]; int main() { freopen("xor.in","r",stdin); freopen("xor.out","w",stdout); n = read(),q = read(); for(int i=1;i<=n;i++)a[i] = read(),s[i] = s[i - 1] ^ a[i]; for(int i=0;i<n;i++) for(int j=i + 1;j<=n;j++)sum[s[i] ^ s[j]]++; for(int i=1;i<=1048576;i++)sum[i] += sum[i - 1]; while(q--) { int k = read(); printf("%d ",upper_bound(sum,sum + 1048576,k - 1) - sum); } }
T3 最小生成树
给n个点,m条计划,每条计划是在[l,r]中任意点连边
每连一条边需要vi的代价
求把所有点连通的最小代价
sol:线段树 + 贪心
发现连的边一定是当前vi最小的边,于是把计划按vi从大到小排序,每次区间覆盖,最后输出一下整棵树的和就可以了
#include<bits/stdc++.h> using namespace std; inline int read() { int x = 0,f = 1;char ch = getchar(); for(;!isdigit(ch);ch = getchar())if(ch == '-') f = -f; for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0'; return x * f; } const int maxn = 1e5 + 10; int n,q; int tag[maxn << 2],sum[maxn << 2],vis[maxn << 2]; struct proj { int l,r,v; bool operator < (const proj &b)const { return v > b.v; } }p[maxn]; #define ls (x << 1) #define rs ((x << 1) | 1) inline void pushup(int x) { sum[x] = sum[ls] + sum[rs]; } inline void pushdown(int x,int l,int r) { if(tag[x]) { int mid = (l + r) >> 1; tag[ls] = tag[x];tag[rs] = tag[x]; sum[ls] = tag[x] * (mid - l + 1);sum[rs] = tag[x] * (r - mid); tag[x] = 0; } if(vis[x])vis[ls] = vis[rs] = 1; } inline void update(int x,int l,int r,int L,int R,int val) { if(L <= l && r <= R) { tag[x] = val; sum[x] = val * (r - l + 1); vis[x] = 1; return; } pushdown(x,l,r); int mid = (l + r) >> 1; if(L <= mid)update(ls,l,mid,L,R,val); if(mid < R)update(rs,mid + 1,r,L,R,val); sum[x] = sum[ls] + sum[rs]; vis[x] = vis[ls] & vis[rs]; } int main() { freopen("kruskal.in","r",stdin); freopen("kruskal.out","w",stdout); n = read() - 1,q = read(); for(int i=1;i<=q;i++)p[i].l = read(),p[i].r = read() - 1,p[i].v = read(); sort(p + 1,p + q + 1); int ans = 0; for(int i=1;i<=q;i++)update(1,1,n,p[i].l,p[i].r,p[i].v); if(!vis[1])cout<<-1; else cout<<sum[1]; }
orz
诅咒:树剖永远写挂
我真是!$^$&!&*!%*%&*!*&$!&
upd:有人引用了我的题解
他好懒
但是他ak了
太强了
%%%