3.08test
依然是题解的代码QAQ,我只会写暴力........
T1:


sol :50points:dp预处理lcp(i,j)+暴力查询
70points:后缀数组
100points:后缀树组,用倍增法构建sa,P.S.求h[]与后缀数组略有不同
详见http://blog.sina.com.cn/s/blog_9a718e380102v0cc.html
//Pionniers du TJ, benissiez-moi par votre Esprits Saints! #include <cstdio> #include <cstring> #include <utility> #include <algorithm> const int maxn = 200010; typedef long long ll; int val[maxn], v[maxn], n, cpt, pos[maxn], i, x, y, q; inline int tu(char ch){ return ch - 'a' + 1; } namespace F{ const int l = 1 << 15; char b[l], *s, *t; inline char gc(){ if (s == t) t = (s = b) + fread(b, 1, l, stdin); return s == t ? EOF : *s++; } inline int rd(){ int x = 0, f = 1; char ch; while ((ch = gc()) < '0' || ch > '9') if (ch == '-') f = -1; while ('0' <= ch && ch <= '9') x = (x << 1) + (x << 3) + ch - '0', ch = gc(); return x * f; } inline char gch(){ char ch; while ((ch = gc()) < 'a' || ch > 'z') ; return ch; } } namespace smt{ typedef std::pair<int, ll> pa; struct ed{ int y, n; } d[maxn]; int e[maxn], l1; pa calc(int x){ int cur = v[x]; ll res = (1ll * cur * (cur - 1) >> 1) * val[x]; for (int p = e[x]; ~p; p = d[p].n){ pa ret = calc(d[p].y); res += 1ll * ret.first * cur * val[x] + ret.second; cur += ret.first; } return std::make_pair(cur, res); } void init(){ for (int i = 1; i <= cpt; ++i) e[i] = -1; } void clear(int x){ l1 = 0; for (int p = e[x]; ~p; p = d[p].n) clear(d[p].y); e[x] = -1; } inline void _c(int x, int y){ /*printf("shh %d %d\n", x, y);*/ d[l1] = (ed){y, e[x]}, e[x] = l1++; } } namespace vt{ struct ed{ int y, n; } d[maxn<<1]; int sz[maxn], de[maxn], fa[maxn], e[maxn], son[maxn], dfn[maxn], top[maxn]; inline void _c(int x, int y){ // printf("%d-%d\n", x, y); static int l1 = 0; d[l1] = (ed){y, e[x]}, e[x] = l1++; d[l1] = (ed){x, e[y]}, e[y] = l1++; } void dfs1(int x){ sz[x] = 1, de[x] = de[fa[x]] + 1; for (int p = e[x], t; ~p; p = d[p].n) if ((t = d[p].y) != fa[x]) if (fa[t] = x, dfs1(t), sz[x] += sz[t], sz[t] > sz[son[x]]) son[x] = t; } void dfs2(int x){ static int tijd = 0; dfn[x] = ++tijd; top[x] = x == son[fa[x]] ? top[fa[x]] : x; if (son[x]) dfs2(son[x]); for (int p = e[x], t; ~p; p = d[p].n) if ((t = d[p].y) != fa[x] && t != son[x]) dfs2(t); } inline int lca(int x, int y){ // puts("lcain"); for (; top[x] ^ top[y]; x = fa[top[x]]) if (de[top[x]] < de[top[y]]) std::swap(x, y); int r = de[x] < de[y] ? x : y; // puts("lcaout"); return r; } inline bool cmp(int x, int y){ return dfn[x] < dfn[y]; } inline void solveeach(){ int m, i, top, t; static int h[maxn], st[maxn]; for (m = F::rd(), i = 1; i <= m; ++i) v[h[i] = pos[F::rd()]]++/*, printf("%d\n", h[i])*/; std::sort(h + 1, h + m + 1, cmp); // for (i = 1; i <= m; ++i) printf("%d\n", h[i]); for (st[top = 1] = i = 1; i <= m; ++i){ for (t = lca(st[top], h[i]); de[t] <= de[st[top - 1]]; ) smt::_c(st[top - 1], st[top]), --top; if (st[top] != t) smt::_c(t, st[top]), st[top] = t; if (st[top] != h[i]) st[++top] = h[i]; } // puts("qlm"); while (top > 1) smt::_c(st[top - 1], st[top]), --top; // puts("builddone"); printf("%lld\n", smt::calc(1).second), smt::clear(1); for (i = 1; i <= m; ++i) v[h[i]]--; } inline void init(){ smt::init(), dfs1(1), dfs2(1); } } namespace trie{ struct ed{ int y, z, n; } d[maxn]; struct node{ int v; node *f, *n[30]; } mem[maxn], *rt; int e[maxn]; inline node *nn(int x){ node *p = mem + ++cpt; return p->v = x, p; } inline node *add(node *p, int x){ // puts("add in"); node *np = nn(p->v + 1), *q, *nq, *op = p; for (; p && !p->n[x]; p = p->f) p->n[x] = np; // puts("w"); if (!p) np->f = rt; else if ((q = p->n[x])->v == p->v + 1) np->f = q; else { (np->f = nq = nn(p->v + 1))->f = q->f, q->f = nq; //puts("std"); for (memcpy(nq->n, q->n, sizeof(q->n)); p && p->n[x] == q; p = p->f) p->n[x] = nq; // puts("cs"); } // puts("cunhuo queren"); return op->n[x]; } inline void _c(int x, int y, int z){ static int l1 = 0; d[l1] = (ed){y, z, e[x]}, e[x] = l1++; d[l1] = (ed){x, z, e[y]}, e[y] = l1++; } void dfs(int x, int fa, node *cur){ pos[x] = cur - mem; //printf("pos %d = %d\n", x, pos[x]); for (int p = e[x], t; ~p; p = d[p].n) if ((t = d[p].y) != fa) dfs(t, x, add(cur, d[p].z)); } inline void solve(){ dfs(1, 0, rt = nn(0)); for (int i = 1; i <= cpt; ++i) vt::e[i] = -1, val[i] = mem[i].v/*, printf("%d: %d\n", i, val[i])*/; for (int i = 2; i <= cpt; ++i) vt::_c(mem[i].f - mem, i); } } int main(){ // freopen("lcp2.in", "r", stdin); // freopen("lcp.out", "w", stdout); for (n = F::rd(), i = 1; i <= n; ++i) trie::e[i] = -1; for (i = 1; i < n; ++i) x = F::rd(), y = F::rd(), trie::_c(x, y, tu(F::gch())); for (trie::solve(), /*puts("sam"),*/ vt::init(), /*puts("start"),*/ q = F::rd(); q--; ) vt::solveeach(); return 0; } //S'il vous plait pardonner mes peches!
T2:
sol :orz sxy大佬的讲解&&ryc大佬的代码
30points:直接跑最小费用流
100points:考虑这是一棵满二叉树,可以直接手动模拟网络流
记录dis[x]表示以x为根的子树到x的有食物的点的最近距离,node[x]为该点的编号
对于一个新加入的点y只有可能走到node[x],x为y或y的祖先
由于是一棵满二叉树所以直接往上找就可以了
模拟网络流的过程,一条边被向上经过打+1tag,向下打-1tag,也就是说tag可以抵消
对于下图(红蓝各表一只)我们可以愉悦地发现这样走显然不是最优的,蓝st往下红st往下才最优
所以当访问新节点y往上找到x时,如果边打了相反的标记,就用dis[x]-1更新dis[y],否则用dis[x]+1更新
因为边打了标记,所以再经过一次相当于退流
然后更新答案直暴力找祖先就行了
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #define inf 1e9 using namespace std; const int Mx=200010; int n,m,p[Mx],c[Mx],dis[Mx],node[Mx],tag[Mx]; long long ans; void update(int x) { if(c[x]) dis[x]=0,node[x]=x;else dis[x]=inf; int lson=x<<1,rson=x<<1|1; if(lson<=n&&dis[lson]+(tag[lson]>=0?1:-1)<dis[x])dis[x]=(tag[lson]>=0?1:-1)+dis[lson],node[x]=node[lson]; if(rson<=n&&dis[rson]+(tag[rson]>=0?1:-1)<dis[x])dis[x]=(tag[rson]>=0?1:-1)+dis[rson],node[x]=node[rson]; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&c[i]); for(int i=n;i>=1;i--) update(i); for(int i=1;i<=m;i++) { scanf("%d",&p[i]); int sumup=0,now=p[i],Dis=inf,Node=0; while(now) { if(Dis>sumup+dis[now]) Dis=sumup+dis[now],Node=node[now]; sumup+=tag[now]<=0?1:-1,now>>=1; } now=p[i]; c[Node]--; while(now!=Node) { if(now>Node) tag[now]--,update(now),now>>=1; else tag[Node]++,update(Node),Node>>=1; } while(now) update(now),now>>=1; printf("%lld ",ans+=Dis); } }
T3:


sol :发现这题被好多人用KD-tree水过了QAQ
拓扑排序后显然可以用二维线段树维护,80points
然后用cdq替代一维,由于有一些单调性之类乱七八糟的性质,所以左半边对右半边的贡献可以直接用线段树维护
//By SiriusRen #include <cstdio> #include <algorithm> using namespace std; const int N=400000; int n,tree[N*16],ans; struct Node{int x,y,a,b,ans;}node[N]; struct Stk{int l,r,k,id,op;Stk(){}Stk(int L,int R,int K,int I,int O){l=L,r=R,k=K,id=I,op=O;}}stk[N]; bool cmp(Node a,Node b){if(a.x!=b.x)return a.x<b.x;return a.y<b.y;} bool Cmp(Stk a,Stk b){if(a.k!=b.k)return a.k<b.k;return a.op>b.op;} void insert(int l,int r,int pos,int num,int f){ if(l==r){if(f)tree[pos]=tree[pos]>f?tree[pos]:f;else tree[pos]=0;return;} int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1; if(mid<num)insert(mid+1,r,rson,num,f); else insert(l,mid,lson,num,f); tree[pos]=tree[lson]>tree[rson]?tree[lson]:tree[rson]; } inline int Max(int x,int y){return x>y?x:y;} int query(int l,int r,int pos,int L,int R){ if(l>=L&&r<=R)return tree[pos]; int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1; if(mid<L)return query(mid+1,r,rson,L,R); else if(mid>=R)return query(l,mid,lson,L,R); else return Max(query(l,mid,lson,L,R),query(mid+1,r,rson,L,R)); } void cdq(int l,int r){ if(l>=r)return; int mid=(l+r)>>1,top=0; cdq(mid+1,r); for(int i=l;i<=mid;i++)stk[++top]=Stk(node[i].y,node[i].b,node[i].a,i,0); for(int i=mid+1;i<=r;i++)stk[++top]=Stk(node[i].y,node[i].y,node[i].x,i,1); sort(stk+1,stk+1+top,Cmp); for(int i=1;i<=top;i++) if(!stk[i].op)node[stk[i].id].ans=Max(node[stk[i].id].ans,query(0,N,1,stk[i].l,stk[i].r)+1); else insert(0,N,1,stk[i].l,node[stk[i].id].ans); for(int i=1;i<=top;i++)if(stk[i].op)insert(0,N,1,stk[i].l,0); cdq(l,mid); } inline int rd(){ char p=getchar();int x=0; while(p<'0'||p>'9')p=getchar(); while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar(); return x; } int main(){ n=rd(); for(int i=1;i<=n;i++)node[i].x=rd(),node[i].y=rd(),node[i].a=rd(),node[i].b=rd(),node[i].ans=1; sort(node+1,node+1+n,cmp),cdq(1,n); for(int i=1;i<=n;i++)ans=ans>node[i].ans?ans:node[i].ans; printf("%d\n",ans); }


浙公网安备 33010602011771号