T1:给定一棵以1号点为根的树,每条边上有字母。定义一个节点的串为该节点走到根节点的路径字符。给定若干个询问,每次询问给定一个点集,询问这若干个点两两之间的lcp总和。

真心对字符串的题不感冒啊。我们考虑构建广义自动机。为什么呢,我们先考虑一个弱智版题目,如果给你一个trie,然后做同样的事情,那么我们完全可以建一个虚树,然后对于每一个节点贡献就是一个关于子树大小的很好求的东西。构建广义后缀自动机之后的parent树其实就是这么一个压缩了一些的trie。然后我们就可以做啦。

由于虚树没写过,SAM有一段时间没写过了,感觉很难写的样子。所以暂(yong)时(yuan)不写了。

T2:给定一棵完全二叉树,每个节点可以容纳xi个东西,给定一个大小为n的点集(里面的点可以重复),分别求对于每一个k(1<=k<=n),这n个点前k个点全部被容纳的代价。容纳代价为这个节点原先的位置到它被容纳节点的距离。

首先很容易得到一个最小费用流算法。但是这还不够,因为我们没有用到一个很重要的,一看就知道最终复杂度是nlogn的条件:完全二叉树。那么肯定是树高大有文章。我们考虑每次费用流,如果我们把源点和汇点去掉的话,然后每一条边是树边的话,每次费用流复杂度就是n的。这还不够,我们发现树高很小,那么我们用树形dp来维护这个费用流的边,每次跑完之后logn更新一下,总复杂度就是nlogn了。

每个节点我们维护一个pair,表示它子树里离它最近的点的距离是多少,这个点是什么。还维护了一个r数组。这特别关键,我们用它来记录这个点的反向边。我们定义向上爬为正方向,向下那就是反向边了。每次爬树高dp的时候我们要考虑反向边的存在,加加减减就好了

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long
 4 #define N 100005
 5 #define INF 1e9
 6 inline LL read(){
 7        LL x=0,f=1; char a=getchar();
 8        while(a<'0' || a>'9') {if(a=='-') f=-1; a=getchar();}
 9        while(a>='0' && a<='9') x=x*10+a-'0',a=getchar();
10        return x*f;
11 }
12 int n,m,c[N],p[N],r[N];
13 LL ans;
14 struct dp{
15     int dep,num;
16     bool operator < (const dp& w)const{
17         return dep<w.dep;
18     }
19 }f[N];
20 dp operator + (const dp& a,const int& b){
21     return (dp){a.dep+b,a.num};
22 }
23 inline void update(int x){
24     if(c[x]) f[x]=(dp){0,x}; else f[x]=(dp){INF,0}; 
25     if((x<<1)<=n) f[x]=min(f[x],f[x<<1]+(r[x<<1]>=0?1:-1));
26     if((x<<1|1)<=n) f[x]=min(f[x],f[x<<1|1]+(r[x<<1|1]>=0?1:-1));
27 }
28 int main(){
29     n=read(); m=read();
30     for(int i=1;i<=n;i++) c[i]=read();
31     for(int i=1;i<=m;i++) p[i]=read();
32     for(int i=n;i;i--) update(i);
33     for(int x,y,i=1;i<=m;i++){
34         x=p[i];
35         dp mn=(dp){INF,0}; int t=0;
36         while(x) mn=min(mn,f[x]+(t)),t+=(r[x]<=0?1:-1),x>>=1;
37         x=p[i]; y=mn.num; c[y]--;
38         while(x!=y){
39             if(x>y) r[x]--,update(x),x>>=1;
40             else r[y]++,update(y),y>>=1;
41         }
42         while(x) update(x),x>>=1;
43         ans+=mn.dep;
44         printf("%lld ",ans);
45     }
46     return 0;
47 }

 

T3:KD_tree板题,第一次写KD_tree

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long
 4 #define N 400005
 5 #define INF  1e9
 6 inline LL read(){
 7        LL x=0,f=1; char a=getchar();
 8        while(a<'0' || a>'9') {if(a=='-') f=-1; a=getchar();}
 9        while(a>='0' && a<='9') x=x*10+a-'0',a=getchar();
10        return x*f;
11 }
12 int n,cnt,num[N],pos[N],root,ans,tmp;
13 struct point{
14     int x,y,a,b,id;
15     inline void get(){
16         x=read(); y=read(); a=read(); b=read();
17     }
18     bool operator < (const point& w)const{
19         if(x==w.x) return y<w.y;
20         return x<w.x;
21     }
22 }p[N];
23 inline bool cmp(int x,int y){
24     return p[x]<p[y];
25 }
26 struct KD_tree{
27     int xl,xr,yb,yt,l,r;
28     int son[2],mx,kind;
29     inline void init(){
30         xl=INF; xr=0; yb=INF; yt=0;
31     }
32 }a[N];
33 inline bool cmpx(const point& a,const point& b){return a.x<b.x;}
34 inline bool cmpy(const point& a,const point& b){return a.y<b.y;}
35 inline void update(int k){a[k].mx=max(a[a[k].son[0]].mx,a[a[k].son[1]].mx);}
36 void build(int& k,int l,int r){
37     k=++cnt; a[k].l=l; a[k].r=r;
38     int F,mid=(l+r)>>1;
39     a[k].init();
40     for(int i=l;i<=r;i++){
41         a[k].xl=min(a[k].xl,p[i].x);
42         a[k].xr=max(a[k].xr,p[i].x);
43         a[k].yb=min(a[k].yb,p[i].y);
44         a[k].yt=max(a[k].yt,p[i].y);
45     }
46     if(l==r) return;
47     a[k].kind=F=a[k].xr-a[k].xl>a[k].yt-a[k].yb?0:1;
48     if(!F) nth_element(p+l,p+mid,p+r+1,cmpx);
49     else nth_element(p+l,p+mid,p+r+1,cmpy);
50     build(a[k].son[0],l,mid); build(a[k].son[1],mid+1,r);
51     update(k);
52 }
53 void modify(int k,int x,int val){
54     if(a[k].l==a[k].r) a[k].mx=val;
55     else{
56         int F=(x<=(a[k].l+a[k].r)/2?0:1);
57         modify(a[k].son[F],x,val);
58         update(k);
59     }
60 }
61 int query(int k,int xl,int xr,int yb,int yt){
62     if(a[k].yt<yb || a[k].yb>yt || a[k].xl>xr || a[k].xr<xl) return 0;
63     if(a[k].yt<=yt && a[k].yb>=yb && a[k].xl>=xl && a[k].xr<=xr) return a[k].mx;
64     int ret=0,F=(a[a[k].son[0]].mx>a[a[k].son[1]].mx?0:1); //优化 
65     ret=query(a[k].son[F],xl,xr,yb,yt);
66     if(ret<a[a[k].son[F^1]].mx) ret=max(ret,query(a[k].son[F^1],xl,xr,yb,yt));
67     return ret;
68 }
69 int main(){
70     n=read();
71     for(int i=1;i<=n;i++) num[i]=i,p[i].id=i,p[i].get();
72     sort(num+1,num+1+n,cmp);
73     build(root,1,n);
74     for(int i=1;i<=n;i++) pos[p[i].id]=i;
75     for(int x,i=n;i;i--){
76         x=pos[num[i]];
77         tmp=query(root,p[x].x,p[x].a,p[x].y,p[x].b)+1;
78         ans=max(ans,tmp);
79         modify(root,x,tmp);
80     }
81     printf("%d\n",ans);
82     return 0;
83 }