2019 6.30

  AK simulation game that does not still have to write a summary. The title is still very good. What I am cooking.

Topic better understand the data range n, m <= 5000. Of course it is easy to think of the tree dp I think is the need for a change to the root dp twice.

Some students find that this is a problem is the direct right of the center of gravity of a point we can find the right point of its center of gravity, and then directly calculate the answer to a complicated course of nm.

Of course there is a method to start to answer all the points as depots have figured out the path and then modify the time affected some statistics. Complex is nm. The

When n reaches 100,000 it does not seem so friendly and ideas should partition from the point of departure, but every time you modify the dynamic point clearly divide and conquer the problem -> dotted tree problem. (Of course, I learned a few days to learn very ignorant of this code is not able to force myself to write)

So before leaving the pit. Put Exam Code:

//#include<bits/stdc++.h>
#include<iomanip>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<deque>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<stack>
#include<algorithm>
#include<vector>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<map>
#define INF 1000000000
#define ll long long
#define min(x,y) (x>y?y:x)
#define max(x,y) (x>y?x:y)
#define RI register ll
#define up(p,i,n) for(ll i=p;i<=n;++i)
#define db double
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline ll read()
{
    ll x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
const int MAXN = 10010 ;
 // DP complexity tree-root operation to consider changing nm
 // Note opening Long Long 
int n-, m, len, Minn, SUM;
 int G [MAXN], SZ [MAXN], F [MAXN], D [MAXN];
 int LIN [MAXN], NEX [MAXN << . 1 ], Ver [MAXN << . 1 ], E [MAXN << . 1 ]; 
inline void the Add ( int X, int Y, int Z) 
{ 
    Ver [ ++ len] = Y; NEX [len] LIN = [X]; LIN [X] = len; E [len] = Z; 
    Ver [ ++ len] = X; NEX [len] LIN = [Y] ; LIN [Y] = len; E [len] = Z; 
} 
inline void DFS (int x,int father)
{
    sz[x]=g[x];d[x]=0;
    for(int i=lin[x];i;i=nex[i])
    {
        int tn=ver[i];
        if(tn==father)continue;
        dfs(tn,x);
        sz[x]+=sz[tn];
        d[x]+=d[tn]+sz[tn]*e[i];
    }
    return;
}
inline void dp(int x,int father)
{
    minn=min(minn,f[x]);
    for(int i=lin[x];i;i=nex[i])
    {
        int tn=ver[i];
        if(tn==father)continue;
        f[tn]=d[tn]+(sum-sz[tn])*e[i]+(f[x]-d[tn]-sz[tn]*e[i]);
        dp(tn,x);
    }
}
int main()
{
    //freopen("1.in","r",stdin);
    //freopen("game.in","r",stdin);
    //freopen("game.out","w",stdout);
    n=read();m=read();
    for(int i=1;i<n;++i)
    {
        int x,y,z;
        x=read();y=read();z=read();
        add(x,y,z);
    }
    for(int i=1;i<=m;++i)
    {
        int x,y;
        x=read();y=read();
        g[x]+=y;minn=INF;
        dfs(1,0);//printf("%d\n",d[1]);
        f[1]=d[1];sum=sz[1];
        dp(1,0);
        printf("%lld\n",minn);
    }
    return 0;
}
View Code

This question has written a long time ago, thanks to the tree line was listening to a wave of consolidation to understood.

In fact, the difference is bare tree and then finally merged at the maximum demand on the line, of course, a low complexity near nlogn complexity.

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<vector>
#include<ctime>
#define ll long long
#define INF 2147483646
#define R register
#define r(i) t[i].r
#define l(i) t[i].l
#define sum(i) t[i].sum
#define v(i) t[i].v
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
inline void put(int x)
{
    x<0?putchar('-'),x=-x:0;
    int num=0;char ch[50];
    while(x)ch[++num]=x%10+'0',x/=10;
    num==0?putchar('0'):0;
    while(num)putchar(ch[num--]);
    putchar('\n');return;
}
const int MAXN=100002;
int n,m,cnt,num;
int lin[MAXN<<1],ver[MAXN<<1],nex[MAXN<<1],len;
int a[MAXN],b[MAXN],f[MAXN],fa[MAXN],lca[MAXN],s[MAXN],s1[MAXN],vis[MAXN],root[MAXN],ans[MAXN];
vector<int>q[MAXN],q1[MAXN];
struct wy
{
    int l,r;
    int sum;//次数
    int v;//价值
}t[MAXN<<6];
inline void add(int x,int y)
{
    ver[++len]=y;
    nex[len]=lin[x];
    lin[x]=len;
}
inline void discrete()
{
    sort(b+1,b+1+m);
    for(int i=1;i<=m;++i)if(i==1||b[i]!=b[cnt])b[++cnt]=b[i];
    for(int i=1;i<=m;++i)a[i]=lower_bound(b+1,b+1+cnt,a[i])-b;
}
inline int getfather(int x){return x==f[x]?x:f[x]=getfather(f[x]);}
inline int max(int x,int y){return x>y?x:y;}
inline int min(int x,int y){return x>y?y:x;}
inline void tarjan(int x)
{
    vis[x]=1;
    for(int i=lin[x];i;i=nex[i])
    {
        int tn=ver[i];
        if(vis[tn]==1)continue;
        tarjan(tn);
        f[tn]=x;fa[tn]=x;
        vis[tn]=2;
    }
    for(unsigned int i=0;i<q[x].size();++i)
    {
        int tn=q[x][i];
        if(vis[tn]==2)lca[q1[x][i]]=getfather(tn);
    }
    return;
}
inline void change(int &p,int l,int r,int x,int d)
{
    if(p==0)p=++num;
    if(l==r){sum(p)+=d,v(p)=l;return;}
    int mid=(l+r)>>1;
    if(x<=mid)change(l(p),l,mid,x,d);
    else change(r(p),mid+1,r,x,d);
    sum(p)=max(sum(l(p)),sum(r(p)));
    v(p)=sum(l(p))>=sum(r(p))?v(l(p)):v(r(p));
    return;
}
inline int merge(int x,int y,int l,int r)
{
    if(x==0||y==0)return x+y;
    if(l==r){sum(x)+=sum(y);return x;}
    int mid=(l+r)>>1;
    l(x)=merge(l(x),l(y),l,mid);
    r(x)=merge(r(x),r(y),mid+1,r);
    sum(x)=max(sum(l(x)),sum(r(x)));
    v(x)=sum(l(x))>=sum(r(x))?v(l(x)):v(r(x));
    return x;
}
inline void dfs(int x)
{
    vis[x]=1;
    for(int i=lin[x];i;i=nex[i])
    {
        int tn=ver[i];
        if(vis[tn]==1)continue;
        dfs(tn);
        root[x]=merge(root[x],root[tn],1,cnt);
    }
    if(sum(root[x])==0)ans[x]=0;
    else ans[x]=v(root[x]);
    return;
}
int main()
{
    //freopen("1.in","r",stdin);
    //freopen("rain.in","r",stdin);
    //freopen("rain.out","w",stdout);
    n=read();m=read();
    for(int i=1;i<n;++i)
    {
        int x,y;f[i]=i;
        x=read();y=read();
        add(x,y);add(y,x);
    }
    f[n]=n;
    for(int i=1;i<=m;++i)
    {
        s[i]=read();s1[i]=read();
        a[i]=b[i]=read();
        if(s[i]==s1[i]){lca[i]=s[i];continue;}
        q[s[i]].push_back(s1[i]);
        q1[s[i]].push_back(i);
        q[s1[i]].push_back(s[i]);
        q1[s1[i]].push_back(i);
    }
    discrete();
    tarjan(1);
    for(int i=1;i<=m;++i)
    {
        change(root[s[i]],1,cnt,a[i],1);
        change(root[s1[i]],1,cnt,a[i],1);
        change(root[lca[i]],1,cnt,a[i],-1);
        if(fa[lca[i]])change(root[fa[lca[i]]],1,cnt,a[i],-1);
    }
    memset(vis,0,sizeof(vis));
    dfs(1);
    for(int i=1;i<=n;++i)put(b[ans[i]]);
    return 0;
}
View Code

虽然第一次学习哈夫曼树 但是 我对它的理解可以说是非常的深,我明白它在干什么。。

当然 这都是源于我的假贪心 。 我原本的思路是这样的 显然 si越小越好,那么 还要满足si不是sj的前缀。显然假设我si先取最小的我可能面临着字符串不够用的情况。

但是 我有一种很巧妙的发现实 每一个si都可以再多生成k个节点 然后虽然长度+1但是字符串更多了 把si扔掉那么现在所有的字符串都是合法的,然后 给ai排个序求一波答案即可。

当然这个贪心并不是最优的所以是错误的贪心 以为我不知道哪个节点延伸 哪个节点不延伸 可以一个节点延伸多次比另一个节点不延伸 更优 因为这样可以保证哪个最大的ai能匹配上最小的si

这我都是不知道的无法控制 自然这个贪心就显得 不太行了。

听鑫神讲了波课 才发现我这个贪心正是哈夫曼树的逆过程。。。没想到倒着搞就是答案。。太菜了。。

试想一下这几个节点我不知道深度是多少 但是我可以利用合并来合并出最优的结果。这个过程和上述过程完全相反 但是却可以得到最优的答案 因为堆的贪心。

至于第二问则是求出si 最小也就是哪个字符串最短 也就是向下延伸的最少自然对于正过程就是字符串合并整体层数越小越好那么在答案最优的情况下层数小的优先即可。

//#include<bits/stdc++.h>
#include<iomanip>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<deque>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<stack>
#include<algorithm>
#include<vector>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<map>
#define INF 1000000000
#define ll long long
#define min(x,y) (x>y?y:x)
#define max(x,y) (x>y?x:y)
#define RI register ll
#define up(p,i,n) for(ll i=p;i<=n;++i)
#define db double
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline ll read()
{
    ll x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
//或许是因为梦的缘故 琉璃之人追逐幻影 ---龙族
ll n,k;
struct wy
{
    ll sum,depth;
    ll friend operator <(wy a,wy b)
    {
        return a.sum==b.sum?a.depth>b.depth:a.sum>b.sum;
    }
};
ll sum,ans;
priority_queue<wy> q;
signed main()
{
    //freopen("1.in","r",stdin);
    n=read();k=read();
    for(ll i=1;i<=n;++i)q.push((wy){read(),0});
    if((n-1)%(k-1)!=0)
    {
        ll w=k-1-((n-1)%(k-1));
        for(ll i=1;i<=w;++i)q.push((wy){0,0});
    }
    while(q.size()!=1)
    {
        ll cnt=0,w=0;
        for(ll i=1;i<=k;++i)
        {
            w=max(w,q.top().depth);
            cnt+=q.top().sum;
            q.pop();
        }
        sum+=cnt;
        q.push((wy){cnt,w+1});
    }
    printf("%lld\n",sum);
    printf("%lld",q.top().depth);
    return 0;
}
View Code

Guess you like

Origin www.cnblogs.com/chdy/p/11119698.html