A. PERFECT NUMBER PROBLEM
一开始想打表,发现实在太慢了,最后百度的perfect number...
#include <cstdio> using namespace std; int main() { printf("6\n28\n496\n8128\n33550336\n"); return 0; }
B. Greedy HOUHOU
待补
C. Angry FFF Party
待补
D. Match Stick Game
待补
E. Card Game
待补
F. Information Transmitting
待补
G. tsy's number
待补
H. Coloring Game
待补
I. Max answer
待补
J. Distance on the tree
在线处理有点麻烦,没办法避免主席树
所以我们考虑将查询的$k$排序后离线做,每询问一次,就把边权小于$k$的边计数设为$1$(由于$k$是递增的,所以每条边只会遍历到一次,复杂度$O(N)$),于是问题转化为求$u$到$v$的路径上计数的和
我的做法是先把整棵树树链剖分上去,然后对于每条链维护一个树状数组,记录的是从顶点到链上某一位置的计数之和
于是可以处理每次查询了:如果这条链完全包含在路径内,将整条链的区间和加到$ans$中;否则只加入区间的某一段之和(所以在树剖的时候,需要记录每个顶点在链上的位置)
动态开数组是C++课上学到的hhh
#include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int N=100005; struct tri { int x,y,w,id; tri() { } tri(int a,int b,int c,int d=0) { x=a,y=b,w=c,id=d; } }; inline bool operator < (tri a,tri b) { return a.w<b.w; } struct Tree { int *t,sz,sum; Tree() { t=NULL; sz=sum=0; } ~Tree() { delete []t; } void Init(int size) { sz=size; t=new int[sz+5]; for(int i=1;i<=sz;i++) t[i]=0; } inline int lowbit(int x) { return x&(-x); } inline void Add(int pos) { sum++; while(pos<=sz) t[pos]++,pos+=lowbit(pos); } inline int Query(int pos) { int res=0; while(pos) res+=t[pos],pos-=lowbit(pos); return res; } }t[N]; int n,m; tri e[N],q[N]; vector<int> v[N]; int fa[N],sz[N],dep[N],son[N]; inline void dfs1(int x,int f) { fa[x]=f; sz[x]=1; dep[x]=dep[fa[x]]+1; for(int i=0;i<v[x].size();i++) { int next=v[x][i]; if(next==fa[x]) continue; dfs1(next,x); sz[x]+=sz[next]; if(!son[x] || sz[next]>sz[son[x]]) son[x]=next; } } int top[N],pos[N]; inline void dfs2(int x,int cur) { top[x]=cur; pos[x]=(top[fa[x]]==cur?pos[fa[x]]:0)+1; if(son[x]) dfs2(son[x],cur); if(!son[x]) t[top[x]].Init(pos[x]); for(int i=0;i<v[x].size();i++) { int next=v[x][i]; if(next==son[x] || next==fa[x]) continue; dfs2(next,next); } } int ans[N]; int main() { // freopen("input.txt","r",stdin); scanf("%d%d",&n,&m); for(int i=1;i<n;i++) { int x,y,w; scanf("%d%d%d",&x,&y,&w); e[i]=tri(x,y,w); v[x].push_back(y); v[y].push_back(x); } sort(e+1,e+n); for(int i=1;i<=m;i++) { int x,y,w; scanf("%d%d%d",&x,&y,&w); q[i]=tri(x,y,w,i); } sort(q+1,q+m+1); dfs1(1,0); dfs2(1,1); int p=1; for(int i=1;i<=m;i++) { while(p<n && e[p].w<=q[i].w) { int des=(fa[e[p].x]==e[p].y?e[p].x:e[p].y); t[top[des]].Add(pos[des]); p++; } int res=0; int x=q[i].x,y=q[i].y; while(top[x]!=top[y]) { if(dep[top[x]]>dep[top[y]]) { res+=t[top[x]].Query(pos[x]); x=fa[top[x]]; } else { res+=t[top[y]].Query(pos[y]); y=fa[top[y]]; } } if(dep[x]>dep[y]) res+=t[top[x]].Query(pos[x])-t[top[x]].Query(pos[y]); else res+=t[top[x]].Query(pos[y])-t[top[x]].Query(pos[x]); ans[q[i].id]=res; } for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }
K. MORE XOR
很明显是结论题
我们应当手算依次手算$f(l,r)$,$g(l,r)$,$w(l,r)$的表达式
由于所有运算都是异或,所以只要一个数出现偶数次,它对结果的贡献就是$0$
那么我们计算的$f$,$g$,$w$的表达式,应当表示为多个元素的异或
最后能发现规律:$w$的结果与分别以$l$、$l+1$为起点、每隔四个元素的异或值有关(注意边界)
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N=100005; int T,n,q; int a[N]; int pre[N]; int main() { // freopen("input.txt","r",stdin); scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); memset(pre,0,sizeof(pre)); for(int i=1;i<=n;i++) { if(i<4) pre[i]=a[i]; else pre[i]=a[i]^pre[i-4]; } scanf("%d",&q); while(q--) { int l,r,pnt,ans=0; scanf("%d%d",&l,&r); pnt=r; while(pnt%4!=l%4) pnt--; if(((r-l)/2+1)%2==1) ans^=(pre[pnt]^(l<4?0:pre[l-4])); if(l!=r) { pnt=r; while(pnt%4!=(l+1)%4) pnt--; if(((r-l+1)/2)%2==1) ans^=(pre[pnt]^(l+1<4?0:pre[l+1-4])); } printf("%d\n",ans); } } return 0; }
L. qiqi'tree
待补
M. Subsequence
待补