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);
}

 

posted @ 2017-03-10 02:30  Czarina  阅读(132)  评论(0)    收藏  举报