算法笔记--树的直径 && 树形dp && 虚树 && 树分治 && 树上差分 && 树链剖分

树的直径:

利用了树的直径的一个性质:距某个点最远的叶子节点一定是树的某一条直径的端点。

先从任意一顶点a出发,bfs找到离它最远的一个叶子顶点b,然后再从b出发bfs找到离b最远的顶点c,那么b和c之间的距离就是树的直径。

用dfs也可以。

模板:

const int N=1e6+5;
int head[N];
int dis[N];
bool vis[N];
int cnt=0,b,mxn=0;
struct edge
{
    int to,w,next;
}edge[N];
void add_edge(int u,int v,int w)
{
    edge[cnt].to=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
void bfs(int s)
{
    queue<int>q;
    q.push(s);
    int now,nxt;
    mxn=0;
    b=s;
    mem(dis,0);
    mem(vis,false);
    while(!q.empty())
    {
        now=q.front();
        q.pop();
        for(int i=head[now];~i;i=edge[i].next)
        {
            if(!vis[edge[i].to])
            {
                q.push(edge[i].to);
                vis[edge[i].to]=true;
                dis[edge[i].to]=dis[now]+edge[i].w;
                if(dis[edge[i].to]>mxn)
                {
                    mxn=dis[edge[i].to];
                    b=edge[i].to;
                }
            }
        }
    }
}

poj 2631 Roads in the North

代码:

#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=1e6+5;
int head[N];
int dis[N];
bool vis[N];
int cnt=0,b,mxn=0;
struct edge
{
    int to,w,next;
}edge[N];
void add_edge(int u,int v,int w)
{
    edge[cnt].to=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
void bfs(int s)
{
    queue<int>q;
    q.push(s);
    int now,nxt;
    mxn=0;
    b=s;
    mem(dis,0);
    mem(vis,false);
    while(!q.empty())
    {
        now=q.front();
        q.pop();
        for(int i=head[now];~i;i=edge[i].next)
        {
            if(!vis[edge[i].to])
            {
                q.push(edge[i].to);
                vis[edge[i].to]=true;
                dis[edge[i].to]=dis[now]+edge[i].w;
                if(dis[edge[i].to]>mxn)
                {
                    mxn=dis[edge[i].to];
                    b=edge[i].to;
                }
            }
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int u,v,w;
    mem(head,-1);
    //freopen("in.txt","r",stdin);
    while(cin>>u>>v>>w)add_edge(u,v,w),add_edge(v,u,w);
    bfs(1);
    //cout<
    bfs(b);
    cout<endl;
    //fclose(stdin);
    return 0;
}
View Code

 Codeforces 592D - Super M

思路:

先构建一个虚树,最短路程=m*2-mx(m为虚树的边数,mx为虚树直径),起点s两次dfs时每次都找最小的,最后在两个中再取最小。

代码:

#include
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=130000;
int head[N];
bool vis[N]={false};
int dis[N];
int s,mx,cnt,sum;
bool belong[N]={false};
struct edge
{
    int to,next;
}edge[2*N];
void add_edge(int u,int v)
{
    edge[cnt].to=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
void dfs(int u)
{
    vis[u]=true;
    for(int i=head[u];~i;i=edge[i].next)
    {
        if(!vis[edge[i].to])
        {
            dis[edge[i].to]=dis[u]+1;
            dfs(edge[i].to);
            if(belong[edge[i].to])
            {
                sum+=2;
                belong[u]=true;
                if(dis[edge[i].to]>mx)
                {
                    mx=dis[edge[i].to];
                    s=edge[i].to;
                }
                else if(dis[edge[i].to]==mx)
                {
                    if(edge[i].to<s)
                    {
                        s=edge[i].to;
                    }
                }
            }
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m,u,v,t;
    mem(head,-1);
    cnt=0;
    cin>>n>>m;
    for(int i=0;i1;i++)
    {
        cin>>u>>v;
        add_edge(u,v);
        add_edge(v,u);
    }
    for(int i=0;i>t,belong[t]=true;
    mx=0;
    s=t;
    dfs(t);
    mem(vis,false);
    mem(dis,0);
    sum=0;
    int tt=s;
    dfs(s);
    cout<endl;
    return 0;
}
View Code

poj 1985 Cow Marathon

代码:

#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=2e5+5;
int head[N];
bool vis[N]={false};
int dis[N];
int t,mx,cnt;
struct edge
{
    int to,w,next;
}edge[2*N];
void add_edge(int u,int v,int w)
{
    edge[cnt].to=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
void bfs(int s)
{
    mem(vis,false);
    mem(dis,0);
    vis[s]=true;
    t=s;
    mx=0;
    queue<int>q;
    q.push(s);
    int now,next;
    while(!q.empty())
    {
        now=q.front();
        q.pop();
        for(int i=head[now];~i;i=edge[i].next)
        {
            if(!vis[edge[i].to])
            {
                vis[edge[i].to]=true;
                q.push(edge[i].to);
                dis[edge[i].to]=dis[now]+edge[i].w;
                if(dis[edge[i].to]>mx)
                {
                    mx=dis[edge[i].to];
                    t=edge[i].to;
                }
            }
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m,u,v,w;
    char c;
    cin>>n>>m;
    cnt=0;
    mem(head,-1);
    while(m--)
    {
        cin>>u>>v>>w>>c;
        add_edge(u,v,w);
        add_edge(v,u,w);
    }
    bfs(1);
    bfs(t);
    cout<endl;
    return 0;
}
View Code

 poj 1383 Labyrinth

思路:同树的直径

代码:

#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=1e3+5;
char mp[N][N];
bool vis[N][N];
int n,m,tx,ty,mx;
struct node
{
    int x,y,step;
};
int dir[4][2]={1,0,0,1,-1,0,0,-1};
void bfs(int x,int y)
{
    queueq;
    node now,nxt;
    now.x=x,now.y=y,now.step=0;
    q.push(now);
    while(!q.empty())
    {
        now=q.front();
        vis[now.x][now.y]=true;
        if(now.step>mx)
        {
            mx=now.step;
            tx=now.x;
            ty=now.y;
        }
        q.pop();
        for(int i=0;i<4;i++)
        {
            nxt.x=now.x+dir[i][0];
            nxt.y=now.y+dir[i][1];
            if(0<=nxt.x&&nxt.x0<=nxt.y&&nxt.y'.'&&!vis[nxt.x][nxt.y])
            {
                nxt.step=now.step+1;
                q.push(nxt);
            }
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int T;
    cin>>T;
    while(T--)
    {
        cin>>m>>n;
        for(int i=0;i)
        cin>>mp[i];
        mem(vis,false);
        mx=0;
        for(int i=0;i)
        {
            for(int j=0;j)
            if(mp[i][j]=='.')
            {
                bfs(i,j);
                break;
            }
        }
        mem(vis,false);
        bfs(tx,ty);
        cout<<"Maximum rope length is "<"."<<endl;
    }
    return 0;
}
View Code

树形dp:

hdu 2196 Computer

思路:http://blog.csdn.net/shuangde800/article/details/9732825

代码:

#include
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=1e4+10;
int head[N];
ll dis[N][2];
bool vis[N];
int cnt;
struct edge
{
    int to,w,next;
}edge[N*2];
void add_edge(int u,int v,int w)
{
    edge[cnt].to=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
ll dfs(int u)
{
    vis[u]=true;
    for(int i=head[u];~i;i=edge[i].next)
    {
        if(!vis[edge[i].to])
        {
            dis[u][0]=max(dis[u][0],dfs(edge[i].to)+edge[i].w);
        }
    }
    return dis[u][0];
}
void DFS(int u)
{
    vis[u]=true;
    ll mx1=0,mx2=0;
    int v1,v2;
    for(int i=head[u];~i;i=edge[i].next)
    {
        if(!vis[edge[i].to])
        {
            ll temp=dis[edge[i].to][0]+edge[i].w;
            if(temp>mx1)
            {
                mx2=mx1;
                v2=v1;
                mx1=temp;
                v1=edge[i].to;
            }
            else if(temp==mx1||temp>mx2)
            {
                mx2=temp;
                v2=edge[i].to;
            }
        }
    }
    int temp=dis[u][1];
    if(temp>mx1)
    {
        mx2=mx1;
        v2=v1;
        mx1=temp;
        v1=-1;
    }
    else if(temp==mx1||temp>mx2)
    {
        mx2=temp;
        v2=-1;
    }
    for(int i=head[u];~i;i=edge[i].next)
    {
        if(!vis[edge[i].to])
        {
            if(v1!=edge[i].to)dis[edge[i].to][1]=mx1+edge[i].w;
            else dis[edge[i].to][1]=mx2+edge[i].w;
            DFS(edge[i].to);
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,u,v,w;
    while(cin>>n)
    {
        mem(head,-1);
        cnt=0;
        for(int i=2;i<=n;i++)
        {
            cin>>u>>w;
            add_edge(i,u,w);
            add_edge(u,i,w);
        }
        mem(dis,0);
        mem(vis,false);
        dfs(1);
        mem(vis,false);
        DFS(1);
        for(int i=1;i<=n;i++)cout<0],dis[i][1])<<endl;
    }
    return 0;
}
View Code

HDU 1520

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int N = 6e3 + 10;
int dp[N][2], a[N];
vector<int> g[N];
int fa[N];
int dfs(int u, int f) {
    if(~dp[u][f]) return dp[u][f];
    dp[u][f] = 0;
    if(f) dp[u][f] = a[u];
    for (int v : g[u]) {
        if(f) dp[u][f] += dfs(v, 0);
        else dp[u][f] += max(dfs(v, 1), dfs(v, 0));
    }
    return dp[u][f];
}
int main() {
    int n, u, v, rt;
    while(~scanf("%d", &n)) {
        for (int i = 1; i <= n; ++i) scanf("%d", &a[i]), g[i].clear();
        for (int i = 1; i <= n; ++i) scanf("%d %d", &u, &v), g[v].pb(u), fa[u] = v;
        for (int i = 1; i <= n; ++i) if(!fa[i]) rt = i;
        mem(dp, -1);
        printf("%d\n", max(dfs(rt, 0), dfs(rt, 1)));
    }
    return 0;
}
View Code

HDU 1561

思路:树上分组背包

dp[i][j]:表示以i为根节点选取j个的最大值

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int N = 205;
LL dp[N][N];
int w[N];
vector<int> g[N];
int n, m, a, b;
void dfs(int u) {
    for (int v : g[u]) {
        dfs(v);
    }
    for (int v : g[u]) {
        for (int i = m; i >= 0; --i) {
            for (int j = i; j >= 0; --j) {
                dp[u][i] = max(dp[u][i], dp[u][i-j] + dp[v][j]);
            }
        }
    }
    if(u) {
        for (int j = m; j >= 1; --j) {
            dp[u][j] = dp[u][j-1] + w[u];
        }
    }
}
int main() {
    while(~scanf("%d %d", &n, &m) && (n || m)) {
        for (int i = 0; i <= n; ++i) g[i].clear();
        for (int i = 1; i <= n; ++i) {
            scanf("%d %d", &a, &b);
            g[a].pb(i);
            w[i] = b;
        }
        for (int i = 0; i <= n; ++i) for (int j = 0; j <= m; ++j) dp[i][j] = 0;
        dfs(0);
        printf("%lld\n", dp[0][m]);
    }
    return 0;
}
View Code

POJ 1741

思路:点分治

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
#include
#include
#include
#include
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int N = 1e4 + 5;
const int INF = 0x3f3f3f3f;
int son[N], n, k, u, v, w, ans = 0;
vector g[N];
vector<int> deep;
bool vis[N];
void get_sz(int u, int o) {
    son[u] = 1;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        if(!vis[v] && v != o) {
            get_sz(v, u);
            son[u] += son[v];
        }
    }
}
pii get_center(int u, int o, int tot) {
    pii res = mp(INF, -1);
    int m = 0, tmp = 1;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        if(!vis[v] && v != o) {
            res = min(res, get_center(v, u, tot));
            m = max(m, son[v]);
            tmp += son[v];
        }
    }
    m = max(m, tot-tmp);
    res = min(res, mp(m, u));
    return res;
}
void get_deep(int u, int o, int d) {
    deep.pb(d);
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        int w = g[u][i].se;
        if(!vis[v] && v != o) {
            get_deep(v, u, d + w);
        }
    }
}
int cal() {
    int res = 0;
    sort(deep.begin(), deep.end());
    for (int l = 0, r = deep.size()-1; l < r; ) {
        if(deep[l] + deep[r] <= k) res += r - l++;
        else r--;
    }
    deep.clear();
    return res;
}
void solve(int u) {
    get_sz(u, u);
    pii p = get_center(u, u, son[u]);
    int c = p.se;
    vis[c] = true;
    get_deep(c, c, 0);
    ans += cal();
    for (int i = 0; i < g[c].size(); ++i) {
        int v = g[c][i].fi;
        if(!vis[v]) solve(v);
    }
    for (int i = 0; i < g[c].size(); ++i) {
        int v = g[c][i].fi;
        int w = g[c][i].se;
        if(!vis[v]) {
            get_deep(v, v, w);
            ans -= cal();
        }
    }
    vis[c] = false;
}
int main() {
    while(~scanf("%d %d", &n, &k) && (n || k)) {
        for (int i = 1; i <= n; ++i) g[i].clear(), son[i] = 0;
        for (int i = 1; i < n; ++i) scanf("%d %d %d", &u, &v, &w), g[u].pb({v, w}), g[v].pb({u, w});
        ans = 0;
        solve(1);
        printf("%d\n", ans);
    }
    return 0;
}
View Code

CodeForces 219D

思路:

dp[i][0]:以i为根的的子树中需要反转多少条边

dp[i][1]:以i为根需要反转多少条边

其中 dp[1][1] = dp[1][0]

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
#include
#include
#include
#include
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int N = 2e5 + 5;
const int INF = 0x3f3f3f3f;
vector g[N];
int dp[N][2];
int n, u, v;
void dfs(int u, int o) {
    dp[u][0] = 0;
    for (pii p : g[u]) {
        int v = p.fi;
        int w = p.se;
        if(v == o) continue;
        dfs(v, u);
        dp[u][0] += dp[v][0] + w;
    }
}
void DFS(int u, int o) {
    if(u == 1) dp[u][1] = dp[u][0];
    for (pii p : g[u]) {
        int v = p.fi;
        int w = p.se;
        if(v == o) continue;
        if(w) dp[v][1] = dp[u][1] - 1;
        else dp[v][1] = dp[u][1] + 1;
        DFS(v, u);
    }
}
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) g[i].clear();
    for (int i = 1; i < n; ++i) {
        scanf("%d %d", &u, &v);
        g[u].pb({v, 0});
        g[v].pb({u, 1});
    }
    dfs(1, 1);
    DFS(1, 1);
    int mn = INF;
    for (int i = 1; i <= n; ++i) mn = min(mn, dp[i][1]);
    printf("%d\n", mn);
    for (int i = 1; i <= n; ++i) if(dp[i][1] == mn) printf("%d ", i);
    printf("\n");
    return 0;
}
View Code

POJ 1155

思路:树上分组背包,注意每个节点背包容量不能跑满,跑子树中叶子节点的个数

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
#include
#include
#include
#include
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int N = 3e3 + 5;
const int INF = 0x3f3f3f3f;
int dp[N][N], cnt[N], n, m, k, a, c;
vector g[N];
int dfs(int u) {
    cnt[u] = 0;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        cnt[u] += dfs(v);
    }
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        int w = g[u][i].se;
        for (int i = cnt[u]; i >= 0; --i) {
            int up = min(i, cnt[v]);
            for (int j = up; j >= 0; --j) {
                 dp[u][i] = max(dp[u][i], dp[u][i-j] + dp[v][j] - w);
            }
        }
    }
    if(!cnt[u]) cnt[u] = 1;
    return cnt[u];
}
int main() {
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n-m; ++i) {
        scanf("%d", &k);
        for (int j = 1; j <= k; ++j) {
            scanf("%d %d", &a, &c);
            g[i].pb(mp(a, c));
        }
    }
    for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) dp[i][j] = -INF;
    for (int i = n-m+1; i <= n; ++i) scanf("%d", &dp[i][1]);
    dfs(1);
    for (int i = m; i >= 0; --i) if(dp[1][i] >= 0) return 0*printf("%d\n", i);
    return 0;
}
View Code

POJ 1947

思路:还是树上分组背包

dp[i][j]表示以i为根节点的子树中保留j个节点(剩下的也和i相连)的最小切边个数

把每条边的权值看成-1,把每个点的权值看成它所连的边的个数(这样就可以最后加上点的权值来使得放进背包里的抵消掉,没放进背包里的就是要切的边的个数)

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
#include
#include
#include
#include
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int N = 155;
const int INF = 0x3f3f3f3f;
vector<int> g[N];
int dp[N][N], fa[N], n, p, u, v;
int dfs(int u) {
    int tot = g[u].size(), son = 1;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i];
        son += dfs(v);
    }
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i];
        for (int i = son; i >= 1; --i) {
            for (int j = i; j >= 1; --j) {
               dp[u][i] = min(dp[u][i-j] + dp[v][j] - 1, dp[u][i]);
            }
        }
    }
    if(!tot) dp[u][1] = 0;
    else {
        for (int i = son; i >= 1; --i) dp[u][i] = dp[u][i-1] + tot;
    }
    return son;
}
int main() {
    scanf("%d %d", &n, &p);
    for (int i = 1; i < n; ++i) scanf("%d %d", &u, &v), g[u].pb(v), fa[v] = u;
    int rt;
    for (int i = 1; i <= n; ++i) if(!fa[i]) rt = i;
    for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) dp[i][j] = INF;
    dfs(rt);
    int ans = INF;
    for (int i = 1; i <= n; ++i) {
        if(i == rt) ans = min(ans, dp[i][p]);
        else ans = min(ans, dp[i][p]+1);
    }
    printf("%d\n", ans);
    return 0;
}
View Code

HDU 1011

思路:还是树上分组背包

有个坑点,具体见代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
#include
#include
#include
#include
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int N = 105;
LL dp[N][N];
int a[N], b[N], n, m, u, v;
vector<int> g[N];
void dfs(int u, int o) {
    int cnt = (a[u]+19)/20;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i];
        if(v != o) {
            dfs(v, u);
            for (int i = m; i >= 1; --i) {
                for (int j = i; j >= 1; --j) {
                    dp[u][i] = max(dp[u][i-j]+dp[v][j], dp[u][i]);
                }
            }
        }
    }
    for (int i = m; i >= cnt; --i) dp[u][i] = dp[u][i-cnt] + b[u];
    for (int i = 0; i < cnt; ++i) dp[u][i] = 0;//!!!!坑点
    dp[u][0] = 0;
}
int main() {
    while(~scanf("%d %d", &n, &m)) {
        if(n == -1 && m == -1) break;
        for (int i = 1; i <= n; ++i) g[i].clear();
        for (int i = 1; i <= n; ++i) scanf("%d %d", &a[i], &b[i]);
        for (int i = 1; i < n; ++i) scanf("%d %d", &u, &v), g[u].pb(v), g[v].pb(u);
        for (int i = 0; i <= n; ++i) for (int j = 0; j <= m; ++j) dp[i][j] = 0;
        dfs(1, 1);
        printf("%lld\n", dp[1][m]);
    }
    return 0;
}
/*
5 1
21 1
1 1
1 5
1 1
1 2
1 2
1 3
2 4
2 5
*/
View Code

ZOJ - 3627

思路:枚举不往同一个方向走的左边界,算出右边界,然后一起往左或往右,口婴

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
#include
#include
#include
#include
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int N = 1e5 + 5;
int n, p, m, t;
int v[N];
LL sum[N];
int main() {
    while(~scanf("%d %d", &n, &p)) {
        for (int i = 1; i <= n; ++i) scanf("%d", &v[i]);
        scanf("%d %d", &m, &t);
        for (int i = 1; i <= n; ++i) sum[i] = sum[i-1] + v[i];
        LL ans = 0;
        for (int l = max(1, p-t); l <= p; ++l) {
            int r = min(n, min(l+m, p+t));
            LL tmp = sum[r] - sum[l-1];
            int res = t - max(p-l, r-p);
            int ll = max(1, l-res);
            int rr = min(n, r+res);
            tmp += max(sum[rr] - sum[r], sum[l-1] - sum[ll-1]);
            //cout << tmp << endl;
            ans = max(tmp, ans);
        }
        printf("%lld\n", ans);
    }
    return 0;
}
/*
7 4
11 10 2 10 2 20 2
2 3
*/
View Code

HDU 3586

思路:

二分 + 树形dp

dp[i]表示切断i所在子树所有叶子的最小花费

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
#include
#include
#include
#include
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int N = 1e3 + 5;
const int INF = 0x3f3f3f3f;
vector g[N];
LL dp[N];
int n, m, u, v, w;
void dfs(int u, int o, int x) {
    for (pii p : g[u]) {
        int v = p.fi;
        int w = p.se;
        if(v != o) {
            dfs(v, u, x);
            if(w <= x) dp[u] += min((LL)w, dp[v]);
            else dp[u] += dp[v];
        }
    }
    if(!dp[u]) dp[u] = INF;
}
bool ck(int mid) {
    for (int i = 1; i <= n; ++i) dp[i] = 0;
    dfs(1, 1, mid);
    return dp[1] <= m;
}
int main() {
    while(~scanf("%d %d", &n, &m) && (n || m)) {
        for (int i = 1; i <= n; ++i) g[i].clear();
        for (int i = 1; i < n; ++i) scanf("%d %d %d", &u, &v, &w), g[u].pb({v, w}), g[v].pb({u, w});
        int l = 1, r = 1001, mid = l+r >> 1;
        while(l < r) {
            if(ck(mid)) r = mid;
            else l = mid + 1;
            mid = l+r >> 1;
        }
        if(mid <= 1000) printf("%d\n", mid);
        else printf("-1\n");
    }
    return 0;
}
View Code

POJ 3107

思路:

求树的重心

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
#include
#include
#include
#include
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int N = 5e4 + 5;
const int INF = 0x3f3f3f3f;
struct edge {
    int to, nxt;
}edge[N*2];
int son[N], dp[N], head[N], n, u, v, center, cnt = 0;
void add_edge(int u, int v) {
        edge[cnt].to = v;
        edge[cnt].nxt = head[u];
        head[u] = cnt++;
}
void dfs(int u, int o) {
    son[u] = 1;
    int m = 0;
    for (int i = head[u]; ~i; i = edge[i].nxt) {
        int v = edge[i].to;
        if(v != o) {
            dfs(v, u);
            son[u] += son[v];
            m = max(m, son[v]);
        }
    }
    m = max(m, n-son[u]);
    center = min(m, center);
    dp[u] = m;
}
int main() {
    while(~scanf("%d", &n)) {
        for (int i = 1; i <= n; ++i) son[i] = 0, head[i] = -1;
        for (int i = 1; i < n; ++i) scanf("%d %d", &u, &v), add_edge(u, v), add_edge(v, u);
        center = INF;
        dfs(1, 1);
        for (int i = 1; i <= n; ++i) if(dp[i] == center) printf("%d ", i);
        printf("\n");
    }
    return 0;
}
View Code

POJ 3140

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
#include
#include
#include
#include
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define ABS(a) (a > 0) ? (a) : -(a)
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int N = 1e5 + 5;
const LL INF = 0x3f3f3f3f3f3f3f3f;
vector<int> g[N];
int a[N], n, m, u, v;
LL son[N], res, tot;
void dfs(int u, int o) {
    son[u] = a[u];
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i];
        if(v != o) {
            dfs(v, u);
            son[u] += son[v];
            res = min(res, ABS(tot-son[v]-son[v]));
        }
    }
}
int main() {
    int cs = 0;
    while(~scanf("%d %d", &n, &m) && (n || m)) {
        res = INF, tot = 0;
        for (int i = 1; i <= n; ++i) g[i].clear();
        for (int i = 1; i <= n; ++i) scanf("%d", &a[i]), tot += a[i];
        for (int i = 1; i < n; ++i) scanf("%d %d", &u, &v), g[u].pb(v), g[v].pb(u);
        dfs(1, 1);
        printf("Case %d: %lld\n", ++cs, res);
    }
    return 0;
}
View Code

POJ 3162

思路:先树形dp求出离每个点最远的距离,做了这么多题你肯定会了

这道题主要是一个单调队列维护区间极值,然后再用尺取法跑一跑对于每一个右端点,它的左端点在哪里

然后还有建图用链式前向星,poj好几道都卡了这个

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define ABS(a) (a > 0) ? (a) : -(a)
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int N = 1e6 + 5;
const int INF = 0x3f3f3f3f;
struct edge {
    int to, w, nxt;
}edge[N*2];
int head[N], cnt;
LL dp[N][2], dis[N];
int n, m, u, w;
void add_edge(int u, int v, int w) {
    edge[cnt].to = v;
    edge[cnt].w = w;
    edge[cnt].nxt = head[u];
    head[u] = cnt++;
}
void dfs(int u, int o) {
    for (int i = head[u]; ~i; i = edge[i].nxt) {
        int v = edge[i].to;
        int w = edge[i].w;
        if(v != o) {
            dfs(v, u);
            dp[u][0] = max(dp[u][0], dp[v][0] + w);
        }
    }
}
void DFS(int u, int o) {
    pii mx = mp(0, -1), mx1 = mp(0, -1);
    for (int i = head[u]; ~i; i = edge[i].nxt) {
        int v = edge[i].to;
        int w = edge[i].w;
        if(v != o) {
            if(dp[v][0] + w > mx.fi) {
                mx1 = mx;
                mx.fi = dp[v][0] + w;
                mx.se = v;
            }
            else if(dp[v][0] + w >= mx1.fi) {
                mx1.fi = dp[v][0] + w;
                mx1.se = v;
            }
        }
    }
    if(dp[u][1] > mx.fi) {
        mx.fi = dp[u][1];
        mx.se = -1;
    }
    else if(dp[u][1] >= mx1.fi) {
        mx1.fi = dp[u][1];
        mx1.se = -1;
    }
    for (int i = head[u]; ~i; i = edge[i].nxt) {
        int v = edge[i].to;
        int w = edge[i].w;
        if(v != o) {
            if(v == mx.se) dp[v][1] = mx1.fi + w;
            else dp[v][1] = mx.fi + w;
            DFS(v, u);
        }
    }
}
int main() {
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; ++i) head[i] = -1;
    cnt = 0;
    for (int i = 2; i <= n; ++i) scanf("%d %d", &u, &w), add_edge(i, u, w), add_edge(u, i, w);
    dfs(1, 1);
    DFS(1, 1);
    for (int i = 1; i <= n; ++i) dis[i] = max(dp[i][0], dp[i][1]);
    deque<int> q1, q2;
    int l = 1, ans = 0;
    for (int r = 1; r <= n; ++r) {
        while(!q1.empty() && dis[q1.back()] > dis[r]) q1.pop_back();
        q1.push_back(r);
        while(!q2.empty() && dis[q2.back()] < dis[r]) q2.pop_back();
        q2.push_back(r);
        while(l <= r) {
            while(!q1.empty() && q1.front() < l) q1.pop_front();
            while(!q2.empty() && q2.front() < l) q2.pop_front();
            if(dis[q2.front()] - dis[q1.front()] > m) ++l;
            else break;
        }
        ans = max(ans, r-l+1);
    }
    printf("%d\n", ans);
    return 0;
}
View Code

POJ 2152

思路:

这个转移不好想,因为当前节点不仅可以依赖子孙还可以依赖其他节点

这样的话对于当前节点 u 就暴力枚举每个它可能依赖的点 i

dp[u][i]:表示以u为根节点的子树(且 u 依赖 i )的最小花费

son[u]:表示以u为根节点的子树的最小花费,这样的话,只要上面求出来了,这个就求出来了

dp[u][i] = w[i] + sum(min(dp[v][i] - w[i], son[v])) ,其中 u 和 i 之间的距离小于 d[u] , v 是 u 的儿子

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define ABS(a) (a > 0) ? (a) : -(a)
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int N = 1e3 + 5;
const int INF = 0x3f3f3f3f;
int dis[N][N], dp[N][N], son[N], w[N], d[N], head[N];
int T, n, u, v, W, cnt;
struct edge {
    int to, w, nxt;
}edge[N*2];
void add_edge(int u, int v, int w) {
    edge[cnt].to = v;
    edge[cnt].w = w;
    edge[cnt].nxt = head[u];
    head[u] = cnt++;
}
void get_d(int x, int fa, int t) {
    dis[u][x] = t;
    for (int i = head[x]; ~i; i = edge[i].nxt) {
        int v = edge[i].to;
        int w = edge[i].w;
        if(v != fa) get_d(v, x, t+w);
    }
}
void dfs(int u, int o) {
    for (int i = head[u]; ~i; i = edge[i].nxt) {
        int v = edge[i].to;
        if(v != o) {
            dfs(v, u);
        }
    }
    son[u] = INF;
    for (int j = 1; j <= n; ++j) {
        dp[u][j] = INF;
        if(dis[u][j] > d[u]) continue;
        dp[u][j] = w[j];
        int tot = 0;
        for (int i = head[u]; ~i; i = edge[i].nxt) {
            int v = edge[i].to;
            if(v != o) {
                dp[u][j] += min(dp[v][j]-w[j], son[v]);
            }
        }
        //cout << u << " " << j << " " << dp[u][j] << endl;
        son[u] = min(son[u], dp[u][j]);
    }
}
int main() {
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i) head[i] = -1;
        cnt = 0;
        for (int i = 1; i <= n; ++i) scanf("%d", &w[i]);
        for (int i = 1; i <= n; ++i) scanf("%d", &d[i]);
        for (int i = 1; i < n; ++i) {
            scanf("%d %d %d", &u, &v, &W);
            add_edge(u, v, W);
            add_edge(v, u, W);
        }
        for (u = 1; u <= n; ++u) get_d(u, u, 0);
        dfs(1, 1);
        printf("%d\n", son[1]);
    }
    return 0;
}
View Code

虚树:

https://blog.csdn.net/weixin_37517391/article/details/82744605

建树模板:

void Insert(int u) {
    if(top <= 1) {
        stk[++top] = u;
        return ;
    }
    int l = lca(stk[top], u);
    if(l == stk[top]) {
        stk[++top] = u;
        return ;
    }
    while(top > 1 && dfn[stk[top-1]] >= dfn[l]) {
        G[stk[top-1]].pb(stk[top]);
        --top;
    }
    if(dfn[stk[top]] > dfn[l]) {
        G[l].pb(stk[top]);
        stk[top] = l;
    }
    stk[++top] = u;
}
while(top > 1) G[stk[top-1]].pb(stk[top]), --top;
--top;

BZOJ 2286

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define ABS(a) (a > 0) ? (a) : -(a)
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int N = 2e5 + 5e4 + 10;
const int INF = 0x3f3f3f3f;
vector g[N];
vector<int> G[N];
int anc[N][18], mn[N], deep[N], a[N], stk[N], dfn[N];
bool vis[N];
int n, u, v, w, m, k, tot = 0, top = 0;
bool cmp(int a, int b) {
    return dfn[a] < dfn[b];
}
void dfs(int u, int o) {
    deep[u] = deep[o] + 1;
    dfn[u] = ++tot;
    anc[u][0] = o;
    for (int j = 1; j < 18; ++j) anc[u][j] = anc[anc[u][j-1]][j-1];
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        int w = g[u][i].se;
        if(v != o) {
            mn[v] = min(mn[u], w);
            dfs(v, u);
        }
    }
}
int lca(int u, int v) {
    if(deep[u] < deep[v]) swap(u, v);
    for (int i = 17; i >= 0; --i) if(deep[anc[u][i]] >= deep[v]) u = anc[u][i];
    if(u == v) return u;
    for (int i = 17; i >= 0; --i) if(anc[u][i] != anc[v][i]) u = anc[u][i], v = anc[v][i];
    return anc[u][0];
}
void Insert(int u) {
    if(top <= 1) {
        stk[++top] = u;
        return ;
    }
    int l = lca(stk[top], u);
    if(dfn[l] == dfn[stk[top]]) {
        stk[++top] = u;
        return ;
    }
    while(top > 1 && dfn[stk[top-1]] >= dfn[l]) {
        G[stk[top-1]].pb(stk[top]);
        --top;
    }
    if(dfn[stk[top]] > dfn[l]) {
        G[l].pb(stk[top]);
        stk[top] = l;
    }
    stk[++top] = u;
}
LL DFS(int u, int o) {
    LL res = 0;
    for (int i = 0; i < G[u].size(); ++i) {
        int v = G[u][i];
        if(v != o) {
            res += min((LL)mn[v], DFS(v, u));
        }
    }
    G[u].clear();
    if(vis[u]) res = mn[u];
    return res;
}
int main() {
    scanf("%d", &n);
    for (int i = 1; i < n; ++i) scanf("%d %d %d", &u, &v, &w), g[u].pb({v, w}), g[v].pb({u, w});
    mn[1] = INF;
    dfs(1, 1);
    scanf("%d", &m);
    while(m--) {
        scanf("%d", &k);
        for (int i = 1; i <= k; ++i) scanf("%d", &a[i]), vis[a[i]] = true;
        sort(a+1, a+1+k, cmp);
        Insert(1);
        for (int i = 1; i <= k; ++i) Insert(a[i]);
        while(top > 1) G[stk[top-1]].pb(stk[top]), --top;
        printf("%lld\n", DFS(1, 1));
        for (int i = 1; i <= k; ++i) vis[a[i]] = false;
    }
    return 0;
}
View Code

CodeForces 613D

思路:

先建虚树,对于某个点,如果它被染色了,那么切断它和所有子孙中还没有被切断的染色节点的联系

如果它没有被染色,那么如果子孙节点中染色节点超过1才把这个点去掉

代码:

#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 1e5 + 5;
vector<int> g[N], G[N];
int anc[N][20], dfn[N], a[N], deep[N], stk[N], fa[N], sz[N], n, u, v, q, k, res, tot = 0, top = 0;
bool vis[N], f;
void dfs(int u, int o) {
    dfn[u] = ++tot;
    deep[u] = deep[o] + 1;
    anc[u][0] = o;
    for (int i = 1; i < 20; ++i) anc[u][i] = anc[anc[u][i-1]][i-1];
    for (int v : g[u]) {
        if(v != o) {
            fa[v] = u;
            dfs(v, u);
        }
    }
}
int lca(int u, int v) {
    if(deep[u] < deep[v]) swap(u, v);
    for (int i = 19; i >= 0; --i) if(deep[anc[u][i]] >= deep[v]) u = anc[u][i];
    if(u == v) return u;
    for (int i = 19; i >= 0; --i) if(anc[u][i] != anc[v][i]) u = anc[u][i], v = anc[v][i];
    return anc[u][0];
}
bool cmp(int a, int b) {
    return dfn[a] < dfn[b];
}
void Insert(int u) {
    if(top <= 1) {
        stk[++top] = u;
        return ;
    }
    int l = lca(stk[top], u);
    if(l == stk[top]) {
        stk[++top] = u;
        return ;
    }
    while(top > 1 && dfn[stk[top-1]] >= dfn[l]) {
        G[stk[top-1]].pb(stk[top]);
        --top;
    }
    if(dfn[stk[top]] > dfn[l]) {
        G[l].pb(stk[top]);
        stk[top] = l;
    }
    stk[++top] = u;
}
int DFS(int u) {
    int res = 0;
    sz[u] = 0;
    for (int v : G[u]) {
        res += DFS(v);
        sz[u] += sz[v];
    }
    if(vis[u]) res += sz[u], sz[u] = 1;
    else if(sz[u] > 1) res++, sz[u] = 0;
    return res;
}
void clr(int u) {
    for (int v : G[u]) {
        clr(v);
    }
    sz[u] = 0;
    G[u].clear();
}
int main() {
    scanf("%d", &n);
    for (int i = 1; i < n; ++i) scanf("%d %d", &u, &v), g[u].pb(v), g[v].pb(u);
    dfs(1, 1);
    scanf("%d", &q);
    while(q--) {
        scanf("%d", &k);
        for (int i = 1; i <= k; ++i) scanf("%d", &a[i]), vis[a[i]] = true;
        f = false;
        for (int i = 1; i <= k; ++i) {
            if(vis[fa[a[i]]]) {
                printf("-1\n");
                f = true;
                break;
            }
        }
        if(f) {
            for (int i = 1; i <= k; ++i) vis[a[i]] = false;
            continue;
        }
        sort(a+1, a+1+k, cmp);
        Insert(1);
        for (int i = 1; i <= k; ++i) if(a[i] != 1) Insert(a[i]);
        while(top > 1) G[stk[top-1]].pb(stk[top]), --top;
        --top;
        printf("%d\n", DFS(1));
        clr(1);
        for (int i = 1; i <= k; ++i) vis[a[i]] = false;
    }
    return 0;
}
View Code

HihoCoder 1387

思路:这道题只用到了lca, 对于同一种颜色求出它虚树的直径,考虑nlog(n)求解,

每次添加一个节点,对于这种颜色来说直径必定在原来直径的两个点和当前点两两组合其中一个。

求两个颜色的最长路也同理,在两个颜色虚树直径的四个端点中两两组合其中一个。

代码:

#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 1e5 + 10;
vector<int> g[N];
map<string, int> mp;
string s, a, b;
pair<int,pii> diameter[N];
int color[N], anc[N][20], deep[N], n, q, u, v, tot;
void dfs(int u, int o) {
    anc[u][0] = o;
    deep[u] = deep[o] + 1;
    for (int i = 1; i < 20; ++i) anc[u][i] = anc[anc[u][i-1]][i-1];
    for (int v : g[u]) {
        if(v != o) {
            dfs(v, u);
        }
    }
}
inline int lca(int u, int v) {
    if(deep[u] < deep[v]) swap(u, v);
    for (int i = 19; i >= 0; --i) if(deep[anc[u][i]] >= deep[v]) u = anc[u][i];
    if(u == v) return u;
    for (int i = 19; i >= 0; --i) if(anc[u][i] != anc[v][i]) u = anc[u][i], v = anc[v][i];
    return anc[u][0];
}
inline int len(int u, int v) {
    return deep[u] + deep[v] - 2*deep[lca(u, v)];
}
int main() {
    fio;
    while(cin >> n >> q) {
        tot = 0;
        mp.clear();
        for (int i = 1; i <= n; ++i) g[i].clear(), diameter[i] = {-1, {-1, -1}};

        for (int i = 1; i <= n; ++i) {
            cin >> s;
            if(mp.find(s) == mp.end()) mp[s] = ++tot, color[i] = tot;
            else color[i] = mp[s];
        }
        for (int i = 1; i < n; ++i) cin >> u >> v, g[u].pb(v), g[v].pb(u);
        deep[1] = 0;
        dfs(1, 1);
        for (int i = 1; i <= n; ++i) {
            int c = color[i];
            if(diameter[c].fi == -1) diameter[c] = {1, {i, i}};
            else {
                int a = diameter[c].se.fi, b = diameter[c].se.se;
                diameter[c] = max(diameter[c], {len(a, i), {a, i}});
                diameter[c] = max(diameter[c], {len(b, i), {b, i}});
            }
        }
        while(q--) {
            cin >> a >> b;
            if(mp.find(a) == mp.end() || mp.find(b) == mp.end()) cout << -1 << "\n";
            else {
                int u = mp[a], v = mp[b], res = 0;
                int x = diameter[u].se.fi, xx = diameter[u].se.se;
                int y = diameter[v].se.fi, yy = diameter[v].se.se;
                //cout << x << " " << xx << " " << y << " " << yy << endl;
                res = max(res, len(x, y));
                res = max(res, len(x, yy));
                res = max(res, len(xx, y));
                res = max(res, len(xx, yy));
                cout << res+1 << "\n";
            }
        }
    }
    return 0;
}
View Code

https://www.luogu.org/problemnew/show/P3233

坑,会虚不会树

树分治: 

点分治主要步骤:

1.得到树的大小

2.计算当前树的重心

3.从重心出发计算链长

4.计算通过重心的链对答案的贡献

5.对于每个重心的儿子,删去两条链都经过儿子对答案的贡献(有些题目不能这样算,考虑边算子树贡献边加子树信息)

6.按重心分治,递归它的每个儿子

Codeforces E - Digit Tree

思路:A = -B*inv(10^B.length) (%M)

代码:

#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 1e5 + 5;
const int INF = 0x3f3f3f3f;
int n, MOD, u, v, w;
vector g[N];
map<int, int> mp1, mp2;
int inv[N], P[N], son[N];
bool vis[N];
pii center;
LL ans = 0;
LL q_pow(LL n, LL k) {
    if(k < 0) return 0;
    LL res = 1;
    while(k) {
        if(k&1) res = (res * n) % MOD;
        n = (n * n) % MOD;
        k >>= 1;
    }
    return res;
}
int phi(int n) {
    int res = n;
    for (int i = 2; i*i <= n; ++i) {
        if(n%i == 0) {
            res = res/i*(i-1);
            while(n%i == 0) n /= i;
        }
    }
    if(n > 1) res = res/n*(n-1);
    return res;
}
void init() {
    P[0] = 1%MOD;
    for (int i = 1; i < N; ++i) P[i] = P[i-1]*10LL%MOD;
    inv[N-1] = q_pow(P[N-1], phi(MOD)-1);
    for (int i = N-2; i >= 0; --i) inv[i] = inv[i+1]*10LL%MOD;
}
inline void get_sz(int u, int o) {
    son[u] = 1;
    for (pii p : g[u]) {
        int v = p.fi;
        if(v != o && !vis[v]) {
            get_sz(v, u);
            son[u] += son[v];
        }
    }
}
inline void get_center(int u, int o, int tot) {
    int mx = 0;
    for (pii p : g[u]) {
        int v = p.fi;
        if(v != o && !vis[v]) {
            get_center(v, u, tot);
            mx = max(mx, son[v]);
        }
    }
    mx = max(mx, tot - son[u]);
    center = min(center, {mx, u});
}
inline void get_deep(int u, int o, int a, int b, int d) {
    for (pii p : g[u]) {
        int v = p.fi;
        int w = p.se;
        if(v != o && !vis[v]) {
            get_deep(v, u, (w*1LL*P[d]+a)%MOD, (b*10LL+w)%MOD, d+1);
        }
    }
    mp1[a]++, mp2[((MOD-b)*1LL*inv[d])%MOD]++;
}
inline LL cal() {
    LL res = 0;
    for (auto it : mp1) {
        if(mp2.find(it.fi) != mp2.end()) {
            res += 1LL*it.se*mp2[it.fi];
        }
    }
    mp1.clear();
    mp2.clear();
    return res;
}
inline void solve(int u) {
    get_sz(u, u);
    center = {INF, INF};
    get_center(u, u, son[u]);
    int c = center.se;
    vis[c] = true;
    get_deep(c, c, 0, 0, 0);
    ans += cal()-1;
    for (pii p : g[c]) {
        int v = p.fi;
        int w = p.se;
        if(!vis[v]) {
            get_deep(v, c, w%MOD, w%MOD, 1);
            ans -= cal();
        }
    }
    for (pii p : g[c]) {
        int v = p.fi;
        if(!vis[v]) solve(v);
    }
    vis[c] = false;
}
int main() {
    scanf("%d %d", &n, &MOD);
    for (int i = 1; i < n; ++i) scanf("%d %d %d", &u, &v, &w), g[u].pb({v, w}), g[v].pb({u, w});
    init();
    solve(0);
    printf("%lld\n", ans);
    return 0;
}
View Code

Codeforces E - Palindromes in a Tree

思路:对于每条链如果状压后只有一个1或者没有1就说明可以构成回文串

对于每个分治点,如果要计算某个子树上每个点的答案,先把这课子树先清空

(因为这条链必须经过分治点,肯定来自其他子树),还有儿子的答案它父亲肯定也有

最后计算分治点的答案

代码:

#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 2e5 + 5;
const int INF = 0x3f3f3f3f;
vector<int> g[N];
int son[N], cnt[1<<20], n, u, v;
LL ans[N];
char s[N];
bool vis[N];
pii center;
inline void get_sz(int u, int o) {
    son[u] = 1;
    for (int v : g[u]) {
        if(v != o && !vis[v]) {
            get_sz(v, u);
            son[u] += son[v];
        }
    }
}
inline void get_center(int u, int o, int tot) {
    int mx = 0;
    for (int v : g[u]) {
        if(v != o && !vis[v]) {
            get_center(v, u, tot);
            mx = max(mx, son[v]);
        }
    }
    mx = max(mx, tot - son[u]);
    center = min(center, {mx, u});
}
inline void update(int u, int o, int st, int ty) {
    cnt[st] += ty;
    for (int v : g[u]) {
        if(v != o && !vis[v]) {
            update(v, u, st^(1<'a'), ty);
        }
    }
}
inline LL cal(int u, int o, int st) {
    LL res = 0;
    for (int v : g[u]) {
        if(v != o && !vis[v]) {
            res += cal(v, u, st^(1<'a'));
        }
    }
    res += cnt[st];
    for (int i = 0; i < 20; ++i) {
        res += cnt[st^(1<<i)];
    }
    ans[u] += res;
    return res;
}
inline void solve(int u) {
    get_sz(u, u);
    center = {INF, INF};
    get_center(u, u, son[u]);

    int c = center.se;
    vis[c] = true;
    int st = 1<'a';
    update(c, c, st, 1);
    LL tmp = 0;
    for (int v : g[c]) {
        if(!vis[v]) {
            update(v, c, st^(1<'a'), -1);
            tmp += cal(v, c, 1<'a');
            update(v, c, st^(1<'a'), 1);
        }
    }
    tmp += cnt[0];
    for (int i = 0; i < 20; ++i)tmp += cnt[1<<i];
    ans[c] += tmp/2;
    update(c, c, st, -1);
    for (int v : g[c]) {
        if(!vis[v]) solve(v);
    }
    vis[c] = false;
}
int main() {
    scanf("%d", &n);
    for (int i = 1; i < n; ++i) scanf("%d %d", &u, &v), g[u].pb(v), g[v].pb(u);
    scanf("%s", s+1);
    solve(1);
    for (int i = 1; i <= n; ++i) printf("%lld ", ans[i]+1);
    return 0;
}
View Code

POJ 2114

代码:

#include
#include
#include
#include
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 1e4 + 5, NN = 1e7 + 5, M = 1e2 + 5;
const int INF = 0x3f3f3f3f;
vector g[N];
bool vis[N], ans[M];
pii center;
int Q[N], son[N], cnt[NN], n, m, u, w, q;
void get_sz(int u, int o) {
    son[u] = 1;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        if(v != o && !vis[v]) {
            get_sz(v, u);
            son[u] += son[v];
        }
    }
}
void get_center(int u, int o, int tot) {
    int mx = 0;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        if(v != o && !vis[v]) {
            get_center(v, u, tot);
            mx = max(mx, son[v]);
        }
    }
    mx = max(mx, tot - son[u]);
    center = min(center, {mx, u});
}
void update(int u, int o, int len, int ty) {
    cnt[len] += ty;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        int w = g[u][i].se;
        if(v != o && !vis[v]) {
            update(v, u, len+w, ty);
        }
    }
}
void cal(int u, int o, int len) {
    for (int i = 1; i <= m; ++i) {
        if(ans[i]) continue;
        if(Q[i]-len >= 0) if(cnt[Q[i]-len]) ans[i] = true;
    }
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        int w = g[u][i].se;
        if(v != o && !vis[v]) {
            cal(v, u, len+w);
        }
    }
}
void solve(int u) {
    get_sz(u, u);
    center = {INF, INF};
    get_center(u, u, son[u]);
    int c = center.se;
    vis[c] = true;
    update(c, c, 0, 1);
    for (int i = 0; i < g[c].size(); ++i) {
        int v = g[c][i].fi;
        int w = g[c][i].se;
        if(!vis[v]) {
            update(v, c, w, -1);
            cal(v, u, w);
            update(v, c, w, 1);
        }
    }
    update(c, c, 0, -1);
    for (int i = 0; i < g[c].size(); ++i) {
        int v = g[c][i].fi;
        if(!vis[v]) solve(v);
    }
    vis[c] = false;
}
int main() {
    while(~scanf("%d", &n) && n) {
        for (int i = 1; i <= n; ++i) g[i].clear();
        for (int i = 1; i <= n; ++i) {
            while(~scanf("%d", &u) && u) {
                scanf("%d", &w);
                g[i].pb({u, w});
                g[u].pb({i, w});
            }
        }
        m = 0;
        while(~scanf("%d", &q) && q) Q[++m] = q;
        mem(ans, false);
        solve(1);
        for (int i = 1; i <= m; ++i) {
            if(ans[i]) printf("AYE\n");
            else printf("NAY\n");
        }
        printf(".\n");
    }
    return 0;
}
View Code

BZOJ 4016: [FJOI2014]最短路径树问题

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 3e4 + 5;
const int INF = 0x3f3f3f3f;
vector g[N], G[N];
int son[N], n, m, k, u, v, w;
int d[N];
pii D[N], center;
pair<int,LL> res;
bool vs[N], vis[N];
priority_queue, greater > q;
void dijkstra(int s) {
    mem(d, 0x3f);
    d[s] = 0;
    q.push(mp(0, s));
    while(!q.empty()) {
        pii p = q.top();
        q.pop();
        int u = p.se;
        if(d[u] < p.fi) continue;
        for (int i = 0; i < g[u].size(); ++i) {
            int v = g[u][i].fi;
            int w = g[u][i].se;
            if(d[v] > d[u] + w) {
                d[v] = d[u] + w;
                q.push(mp(d[v], v));
            }
        }
    }
}
void dfs(int u) {
    vs[u] = true;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        int w = g[u][i].se;
        if(!vs[v]) {
            if(d[u] + w == d[v]) {
                G[u].pb(mp(v, w));
                G[v].pb(mp(u, w));
                dfs(v);
            }
        }
    }
}
void get_sz(int u, int o) {
    son[u] = 1;
    for (int i = 0; i < G[u].size(); ++i) {
        int v = G[u][i].fi;
        int w = G[u][i].se;
        if(v != o && !vis[v]) {
            get_sz(v, u);
            son[u] += son[v];
        }
    }
}
void get_center(int u, int o, int tot) {
    int mx = 0;
    for (int i = 0; i < G[u].size(); ++i) {
        int v = G[u][i].fi;
        int w = G[u][i].se;
        if(v != o && !vis[v]) {
            get_center(v, u, tot);
            mx = max(mx, son[v]);
        }
    }
    mx = max(mx, tot - son[u]);
    center = min(center, mp(mx, u));
}
void update(int u, int o, int x, int d, int ty) {
    if(ty == 1) {
        if(x > D[d].fi) {
            D[d].fi = x;
            D[d].se = 1;
        }
        else if(x == D[d].fi) D[d].se++;
    }
    else D[d] = mp(0, 0);
    for (int i = 0; i < G[u].size(); ++i) {
        int v = G[u][i].fi;
        int w = G[u][i].se;
        if(v != o && !vis[v]) update(v, u, x+w, d+1, ty);
    }
}
void cal(int u, int o, int x, int d) {
    if(d <= k-1) {
        if(D[k-1-d].fi + x > res.fi && D[k-1-d].se > 0) {
            res.fi = D[k-1-d].fi + x;
            res.se = D[k-1-d].se;
        }
        else if(D[k-1-d].fi + x == res.fi && D[k-1-d].se > 0) {
            res.se += D[k-1-d].se;
        }
    }
    else return;
    for (int i = 0; i < G[u].size(); ++i) {
        int v = G[u][i].fi;
        int w = G[u][i].se;
        if(v != o && !vis[v]) cal(v, u, x+w, d+1);
    }
}
void solve(int u) {
    get_sz(u, u);
    center = {INF, INF};
    get_center(u, u, son[u]);
    int c = center.se;
    vis[c] = true;

    D[0] = mp(0, 1);

    for (int i = 0; i < G[c].size(); ++i) {
        int v = G[c][i].fi;
        int w = G[c][i].se;
        if(!vis[v]) {
            cal(v, c, w, 1);
            update(v, c, w, 1, 1);
        }
    }
    update(c, c, 0, 0, -1);
    for (int i = 0; i < G[c].size(); ++i) {
        int v = G[c][i].fi;
        if(!vis[v]) solve(v);
    }
    vis[c] = false;
}
int main() {
    scanf("%d %d %d", &n, &m, &k);
    for (int i = 1; i <= m; ++i) {
        scanf("%d %d %d", &u, &v, &w);
        g[u].pb(mp(v, w));
        g[v].pb(mp(u, w));
    }
    for (int i = 1; i <= n; ++i) sort(g[i].begin(), g[i].end());
    dijkstra(1);
    dfs(1);

    res = mp(0, 0);
    for (int i = 1; i <= n+1; ++i) D[i] = mp(0, 0);
    solve(1);
    printf("%d %lld\n", res.fi, res.se);
    return 0;
}
View Code

BZOJ 2152: 聪聪可可

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 2e4 + 5;
const int INF = 0x3f3f3f3f;
vector g[N];
int son[N], cnt[3], n, u, v, w;
bool vis[N];
pii center;
LL tot = 0;
void get_sz(int u, int o) {
    son[u] = 1;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        if(v != o && !vis[v]) {
            get_sz(v, u);
            son[u] += son[v];
        }
    }
}
void get_center(int u, int o, int tot) {
    int mx = 0;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        if(v != o && !vis[v]) {
            get_center(v, u, tot);
            mx = max(mx, son[v]);
        }
    }
    mx = max(mx, tot-son[u]);
    center = min(center, mp(mx, u));
}
void cal(int u, int o, int x) {
    tot += cnt[(3-x)%3];
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        int w = g[u][i].se;
        if(v != o && !vis[v]) {
            cal(v, u, (x+w)%3);
        }
    }
}
void update(int u, int o, int x) {
    cnt[x]++;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        int w = g[u][i].se;
        if(v != o && !vis[v]) {
            update(v, u, (x+w)%3);
        }
    }
}
void solve(int u) {
    get_sz(u, u);
    center = mp(INF, INF);
    get_center(u, u, son[u]);
    int c = center.se;
    vis[c] = true;
    cnt[0]++;
    for (int i = 0; i < g[c].size(); ++i) {
        int v = g[c][i].fi;
        int w = g[c][i].se;
        if(!vis[v]) {
            cal(v, c, w%3);
            update(v, c, w%3);
        }
    }
    cnt[0] = cnt[1] = cnt[2] = 0;
    for (int i = 0; i < g[c].size(); ++i) {
        int v = g[c][i].fi;
        if(!vis[v]) {
            solve(v);
        }
    }
    vis[c] = false;
}
int main() {
    scanf("%d", &n);
    for (int i = 1; i < n; ++i) scanf("%d %d %d", &u, &v, &w), g[u].pb({v, w}), g[v].pb({u, w});
    solve(1);
    tot = (tot<<1) + n;
    LL sum = n*1LL*n;
    LL d = __gcd(tot, sum);
    printf("%lld/%lld\n", tot/d, sum/d);
    return 0;
}
View Code

 UVALive - 6900

思路:点分治,树状数组维护前缀最小值

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 2e4 + 5;
const int INF = 0x3f3f3f3f;
vectorint, pii>> g[N];
int son[N], T, n, u, v, c, b, C, ans;
pii center;
bool vis[N];
int bit[N], sz;
vector<int> vc;
void add(int x, int a) {
    while(x <= sz) bit[x] = max(bit[x], a), x += x&-x;
}
int query(int x) {
    int res = 0;
    while(x) res = max(res, bit[x]), x -= x&-x;
    return res;
}
void get_sz(int u, int o) {
    son[u] = 1;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        if(v != o && ! vis[v]) {
            get_sz(v, u);
            son[u] += son[v];
        }
    }
}
void get_center(int u, int o, int tot) {
    int mx = 0;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        if(v != o && !vis[v]) {
            get_center(v, u, tot);
            mx = max(mx, son[v]);
        }
    }
    mx = max(mx, tot - son[u]);
    center = min(center, mp(mx, u));
}
void get_d(int u, int o, int d) {
    vc.pb(d);
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        int w = g[u][i].se.fi;
        if(v != o && !vis[v]) {
            get_d(v, u, d+w);
        }
    }
}
void update(int u, int o, int x, int y) {
    add(lower_bound(vc.begin(), vc.end(), x)-vc.begin()+1, y);
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        int xx = g[u][i].se.fi;
        int yy = g[u][i].se.se;
        if(v != o && !vis[v]) {
            update(v, u, x+xx, y+yy);
        }
    }
}
void cal(int u, int o, int x, int y) {
    if(x > C) return ;
    int id = upper_bound(vc.begin(), vc.end(), C-x) - vc.begin();
    ans = max(ans, query(id)+y);
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        int xx = g[u][i].se.fi;
        int yy = g[u][i].se.se;
        if(v != o && !vis[v]) {
            cal(v, u, x+xx, y+yy);
        }
    }
}
void solve(int u) {
    get_sz(u, u);
    center = mp(INF, INF);
    get_center(u, u, son[u]);
    int c = center.se;
    vis[c] = true;
    get_d(c, c, 0);
    sz = vc.size();
    sort(vc.begin(), vc.end());
    for (int i = 0; i < g[c].size(); ++i) {
        int v = g[c][i].fi;
        int w = g[c][i].se.fi;
        int vv = g[c][i].se.se;
        if(!vis[v]) {
            cal(v, c, w, vv);
            update(v, c, w, vv);
        }
    }
    vc.clear();
    for (int i = 1; i <= sz; ++i) bit[i] = 0;
    for (int i = 0; i < g[c].size(); ++i) {
        int v = g[c][i].fi;
        if(!vis[v]) solve(v);
    }
    vis[c] = false;
}
int main() {
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        for (int i = 1; i < n; ++i) scanf("%d %d %d %d", &u, &v, &c, &b), g[u].pb({v, {c, b}}), g[v].pb({u, {c, b}});
        scanf("%d", &C);
        ans = 0;
        solve(1);
        printf("%d\n", ans);
        for (int i = 1; i <= n; ++i) g[i].clear();
    }
    return 0;
}
View Code

SPOJ FTOUR2

思路:还是套个树状数组,但有点坑

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 2e5 + 5;
const int INF = 0x3f3f3f3f;
vector g[N];
int n, m, k, u, v, w, up;
LL ans = 0;
int bit[N], son[N], crow[N];
pii center;
bool vis[N];
void add(int x, int a) {
    while(x <= up) bit[x] = max(bit[x], a), x += x&-x;
}
int query(int x) {
    int res = -INF;
    if(x > up) x = up;
    while(x) res = max(res, bit[x]), x -= x&-x;
    return res;
}
void get_sz(int u, int o) {
    son[u] = 1;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        if(v != o && !vis[v]) {
            get_sz(v, u);
            son[u] += son[v];
        }
    }
}
void get_center(int u, int o, int tot) {
    int mx = 0;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        if(v != o && !vis[v]) {
            get_center(v, u, tot);
            mx = max(mx, son[v]);
        }
    }
    mx = max(mx, tot-son[u]);
    center = min(center, {mx, u});
}
void get_d(int u, int o, int x) {
    up = max(up, x);
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        if(v != o && !vis[v]) get_d(v, u, x+crow[v]);
    }
}
void update(int u, int o, int x, int y) {
    add(x, y);
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        int w = g[u][i].se;
        if(v != o && !vis[v]) {
            update(v, u, x+crow[v], y+w);
        }
    }
}
void cal(int u, int o, int x, int y) {
    if(x > k) return ;
    int t = query(k-x+1);
    if(t >= 0) ans = max(ans, 1LL*y+t);
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        int w = g[u][i].se;
        if(v != o && !vis[v]) {
            cal(v, u, x+crow[v], y+w);
        }
    }
}
void solve(int u) {
    get_sz(u, u);
    center = {INF, INF};
    get_center(u, u, son[u]);
    int c = center.se;
    vis[c] = true;
    up = 0;
    get_d(c, c, crow[c]+1);
    for (int i = 1; i <= up; ++i) bit[i] = -INF;
    if(crow[c]) add(2, 0);
    else add(1, 0);
    for (int i = 0; i < g[c].size(); ++i) {
        int v = g[c][i].fi;
        int w = g[c][i].se;
        if(!vis[v]) {
            cal(v, c, crow[v], w);
            update(v, c, crow[c]+crow[v]+1, w);
        }
    }
    for (int i = 0; i < g[c].size(); ++i) {
        int v = g[c][i].fi;
        if(!vis[v]) solve(v);
    }
    vis[c] = false;
}
int main() {
    scanf("%d %d %d", &n, &k, &m);
    for (int i = 1; i <= m; ++i) scanf("%d", &u), crow[u] = 1;
    for (int i = 1; i < n; ++i) scanf("%d %d %d", &u, &v, &w), g[u].pb({v, w}), g[v].pb({u, w});
    solve(1);
    printf("%lld\n", max(ans, 0LL));
    return 0;
}
View Code 

边分治:

树上差分:

https://www.cnblogs.com/ice-wing/p/7709311.html

BZOJ 4326: NOIP2015 运输计划

思路:二分+点差分(洛谷卡tarjan求lca

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 3e5 + 5;
vector g[N];
int n, m, u, v, w, tot, mx;
int cnt[N], deep[N], len[N], anc[N][20];
struct node {
    int u, v, a, len;
}a[N];
void dfs(int u, int o) {
    anc[u][0] = o;
    deep[u] = deep[o] + 1;
    for (int i = 1; i < 20; ++i) anc[u][i] = anc[anc[u][i-1]][i-1];
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        int w = g[u][i].se;
        if(v != o) len[v] = len[u] + w, dfs(v, u);
    }
}
int lca(int u, int v) {
    if(deep[u] < deep[v]) swap(u, v);
    for (int i = 19; i >= 0; --i) if(deep[anc[u][i]] >= deep[v]) u = anc[u][i];
    if(u == v) return u;
    for (int i = 19; i >= 0; --i) if(anc[u][i] != anc[v][i]) u = anc[u][i], v = anc[v][i];
    return anc[u][0];
}
void DFS(int u, int o, int w) {
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        int w = g[u][i].se;
        if(v != o) {
            DFS(v, u, w);
            cnt[u] += cnt[v];
        }
    }
    if(cnt[u] == tot) mx = max(mx, w);
}
bool ck(int x) {
    for (int i = 1; i <= n; ++i) cnt[i] = 0;
    tot = 0;
    mx = 0;
    int MX = 0;
    for (int i = 1; i <= m; ++i) {
        if(a[i].len > x) {
            cnt[a[i].u]++;
            cnt[a[i].v]++;
            cnt[a[i].a] -= 2;
            tot++;
        }
        MX = max(MX, a[i].len);
    }
    if(tot == 0) return true;
    DFS(1, 1, 0);
    return MX-mx <= x;
}
int main() {
    scanf("%d %d", &n, &m);
    for (int i = 1; i < n; ++i) scanf("%d %d %d", &u, &v, &w), g[u].pb({v, w}), g[v].pb({u, w});
    dfs(1, 1);
    int l = 0, r = 0;
    for (int i = 1; i <= m; ++i) {
        scanf("%d %d", &a[i].u, &a[i].v);
        a[i].a = lca(a[i].u, a[i].v);
        a[i].len = len[a[i].u] + len[a[i].v] - 2*len[a[i].a];
        r = max(r, a[i].len);
    }
    int mid = l+r >> 1;
    while(l < r) {
        if(ck(mid)) r = mid;
        else l = mid+1;
        mid = l+r >> 1;
    }
    printf("%d\n", mid);
    return 0;
}
View Code 

P3128 [USACO15DEC]最大流Max Flow

思路:边差分

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 5e4 + 5;
vector<int> g[N];
int anc[N][18], fa[N], deep[N], cnt[N], n, k, u, v, a, ans = 0;
void dfs(int u, int o) {
    anc[u][0] = o;
    if(u == 1) fa[u] = 0;
    else fa[u] = o;
    deep[u] = deep[o] + 1;
    for (int i = 1; i < 18; ++i) anc[u][i] = anc[anc[u][i-1]][i-1];
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i];
        if(v != o) dfs(v, u);
    }
}
int lca(int u, int v) {
    if(deep[u] < deep[v]) swap(u, v);
    for (int i = 17; i >= 0; --i) if(deep[anc[u][i]] >= deep[v]) u = anc[u][i];
    if(u == v) return u;
    for (int i = 17; i >= 0; --i) if(anc[u][i] != anc[v][i]) u = anc[u][i], v = anc[v][i];
    return anc[u][0];
}
void DFS(int u, int o) {
    for (int i = 0; i < g[u].size(); ++i){
        int v = g[u][i];
        if(v != o) {
            DFS(v, u);
            cnt[u] += cnt[v];
        }
    }
    ans = max(ans, cnt[u]);
}
int main() {
    scanf("%d %d", &n, &k);
    for (int i = 1; i < n; ++i) scanf("%d %d", &u, &v), g[u].pb(v), g[v].pb(u);
    dfs(1, 1);
    for (int i = 1; i <= k; ++i) {
        scanf("%d %d", &u, &v);
        a = lca(u, v);
        cnt[u]++;
        cnt[v]++;
        cnt[a]--;
        cnt[fa[a]]--;
    }
    DFS(1, 1);
    printf("%d\n", ans);
    return 0;
}
View Code

树链剖分:

https://www.cnblogs.com/ivanovcraft/p/9019090.html

 模板:

const int N = 1e5 + 5;
vector<int> g[N];
int fa[N], dp[N], sz[N], son[N], top[N], dfn[N], to[N], cnt = 0, n;
void dfs1(int u, int o) {
    fa[u] = o;
    sz[u] = 1;
    dp[u] = dp[o] + 1;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i];
        if(v != o) {
            dfs1(v, u);
            sz[u] += sz[v];
            if(sz[v] > sz[son[u]]) son[u] = v;
        }
    }
}
void dfs2(int u, int t) {
    top[u] = t;
    dfn[u] = ++cnt;
    to[cnt] = u;
    if(!son[u]) return ;
    dfs2(son[u], t);
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i];
        if(v != fa[u] && v != son[u]) dfs2(v, v);
    }
}
void add(int u, int v, int x) {
    int fu = top[u], fv = top[v];
    while(fu != fv) {
        if(dp[fu] >= dp[fv]) update(dfn[fu], dfn[u], x, 1, 1, n), u = fa[fu], fu = top[u];
        else update(dfn[fv], dfn[v], x, 1, 1, n), v = fa[fv], fv = top[v];
    }
    if(dfn[u] <= dfn[v]) update(dfn[u], dfn[v], x, 1, 1, n);
    else update(dfn[v], dfn[u], x, 1, 1, n);
}
int sum(int u, int v) {
    int ans = 0, fu = top[u], fv = top[v];
    while(fu != fv) {
        if(dp[fu] >= dp[fv]) ans += query(dfn[fu], dfn[u], 1, 1, n), u = fa[fu], fu = top[u];
        else ans += query(dfn[fv], dfn[v], 1, 1, n), v = fa[fv], fv = top[v];
    }
    if(dfn[u] <= dfn[v]) ans += query(dfn[u], dfn[v], 1, 1, n);
    else ans += query(dfn[v], dfn[u], 1, 1, n);
    return ans;
}
int lca(int u, int v) {
    int fu = top[u], fv = top[v];
    while(fu != fv) {
        if(dp[fu] >= dp[fv]) u = fa[fu], fu = top[u];
        else v = fa[fv], fv = top[v];
    }
    if(dp[u] <= dp[v]) return u;
    else v;
}

 P3384 【模板】树链剖分 

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 1e5 + 5;
vector<int> g[N];
int fa[N], dp[N], sz[N], son[N], top[N], dfn[N], to[N], cnt = 0, n, m, r, MOD;
int a[N], op, x, y, z, u, v, tree[N<<2], lazy[N<<2];
void push_up(int rt) {
    tree[rt] = (tree[rt<<1] + tree[rt<<1|1]) % MOD;
}
void push_down(int rt, int len) {
    lazy[rt<<1] = (lazy[rt<<1] + lazy[rt]) % MOD;
    lazy[rt<<1|1] = (lazy[rt<<1|1] + lazy[rt]) % MOD;
    tree[rt<<1] = (tree[rt<<1] + (len-(len>>1))*1LL*lazy[rt]) % MOD;
    tree[rt<<1|1] = (tree[rt<<1|1] + (len>>1)*1LL*lazy[rt]) % MOD;
    lazy[rt] = 0;
}
void build(int rt, int l, int r) {
    if(l == r) {
        tree[rt] = a[to[l]];
        return ;
    }
    int m = l+r >> 1;
    build(ls);
    build(rs);
    push_up(rt);
}
void update(int L, int R, int x, int rt, int l, int r) {
    if(L <= l && r <= R) {
        lazy[rt] = (lazy[rt] + x) % MOD;
        tree[rt] = (tree[rt] + (r-l+1)*1LL*x) % MOD;
        return ;
    }
    if(lazy[rt]) push_down(rt, r-l+1);
    int m = l+r >> 1;
    if(L <= m) update(L, R, x, ls);
    if(R > m) update(L, R, x, rs);
    push_up(rt);
}
int query(int L, int R, int rt, int l, int r) {
    if(L <= l && r <= R) return tree[rt];
    int ans = 0, m = l+r >> 1;
    if(lazy[rt]) push_down(rt, r-l+1);
    if(L <= m) ans = (ans + query(L, R, ls)) % MOD;
    if(R > m) ans = (ans + query(L, R, rs)) % MOD;
    push_up(rt);
    return ans;
}
void dfs1(int u, int o) {
    fa[u] = o;
    sz[u] = 1;
    dp[u] = dp[o] + 1;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i];
        if(v != o) {
            dfs1(v, u);
            sz[u] += sz[v];
            if(sz[v] > sz[son[u]]) son[u] = v;
        }
    }
}
void dfs2(int u, int t) {
    top[u] = t;
    dfn[u] = ++cnt;
    to[cnt] = u;
    if(!son[u]) return ;
    dfs2(son[u], t);
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i];
        if(v != fa[u] && v != son[u]) dfs2(v, v);
    }
}
void add(int u, int v, int x) {
    int fu = top[u], fv = top[v];
    while(fu != fv) {
        if(dp[fu] >= dp[fv]) update(dfn[fu], dfn[u], x, 1, 1, n), u = fa[fu], fu = top[u];
        else update(dfn[fv], dfn[v], x, 1, 1, n), v = fa[fv], fv = top[v];
    }
    if(dfn[u] <= dfn[v]) update(dfn[u], dfn[v], x, 1, 1, n);
    else update(dfn[v], dfn[u], x, 1, 1, n);
}
int sum(int u, int v) {
    int ans = 0, fu = top[u], fv = top[v];
    while(fu != fv) {
        if(dp[fu] >= dp[fv]) ans = (ans + query(dfn[fu], dfn[u], 1, 1, n)) % MOD, u = fa[fu], fu = top[u];
        else ans = (ans + query(dfn[fv], dfn[v], 1, 1, n)) % MOD, v = fa[fv], fv = top[v];
    }
    if(dfn[u] <= dfn[v]) ans = (ans + query(dfn[u], dfn[v], 1, 1, n)) % MOD;
    else ans = (ans + query(dfn[v], dfn[u], 1, 1, n)) % MOD;
    return ans;
}
int lca(int u, int v) {
    int fu = top[u], fv = top[v];
    while(fu != fv) {
        if(dp[fu] >= dp[fv]) u = fa[fu], fu = top[u];
        else v = fa[fv], fv = top[v];
    }
    if(dp[u] <= dp[v]) return u;
    else v;
}
int main() {
    scanf("%d %d %d %d", &n, &m, &r, &MOD);
    for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    for (int i = 1; i < n; ++i) scanf("%d %d", &u, &v), g[u].pb(v), g[v].pb(u);
    dfs1(r, r);
    dfs2(r, r);
    build(1, 1, n);
    for (int i = 1; i <= m; ++i) {
        scanf("%d", &op);
        if(op == 1) {
            scanf("%d %d %d", &x, &y, &z);
            add(x, y, z);
        }
        else if(op == 2) {
            scanf("%d %d", &x, &y);
            printf("%lld\n", sum(x, y));
        }
        else if(op == 3) {
            scanf("%d %d", &x, &z);
            update(dfn[x], dfn[x]+sz[x]-1, z, 1, 1, n);
        }
        else {
            scanf("%d", &x);
            printf("%d\n", query(dfn[x], dfn[x]+sz[x]-1, 1, 1, n));
        }
    }
    return 0;
}
View Code

 P2146 [NOI2015]软件包管理器 

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 1e5 + 5;
vector<int> g[N];
int sz[N], fa[N], dp[N], son[N], top[N], dfn[N], to[N], cnt = 0;
int n, q, u, x;
int tree[N<<2], lazy[N<<2];
char s[20];
void push_up(int rt) {
    tree[rt] = tree[rt<<1] + tree[rt<<1|1];
}
void push_down(int rt, int len) {
    lazy[rt<<1] = lazy[rt];
    lazy[rt<<1|1] = lazy[rt];
    tree[rt<<1] = lazy[rt]*(len-(len>>1));
    tree[rt<<1|1] = lazy[rt]*(len>>1);
    lazy[rt] = -1;
}
void build(int rt, int l, int r) {
    lazy[rt] = -1;
    if(l == r) return ;
    int m = l+r >> 1;
    build(ls);
    build(rs);
}
void update(int L, int R, int x, int rt, int l, int r) {
    if(L <= l && r <= R) {
        tree[rt] = x*(r-l+1);
        lazy[rt] = x;
        return ;
    }
    if(~lazy[rt]) push_down(rt, r-l+1);
    int m = l+r >> 1;
    if(L <= m) update(L, R, x, ls);
    if(R > m) update(L, R, x, rs);
    push_up(rt);
}
int query(int L, int R, int rt, int l, int r) {
    if(L <= l && r <= R) return tree[rt];
    if(~lazy[rt]) push_down(rt, r-l+1);
    int ans = 0, m = l+r >> 1;
    if(L <= m) ans += query(L, R, ls);
    if(R > m) ans += query(L, R, rs);
    push_up(rt);
    return ans;
}
void dfs1(int u, int o) {
    fa[u] = o;
    dp[u] = dp[o] + 1;
    sz[u] = 1;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i];
        if(v != o) {
            dfs1(v, u);
            sz[u] += sz[v];
            if(sz[v] > sz[son[u]]) son[u] = v;
        }
    }
}
void dfs2(int u, int t) {
    dfn[u] = ++cnt;
    to[cnt] = u;
    top[u] = t;
    if(!son[u]) return ;
    dfs2(son[u], t);
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i];
        if(v != son[u] && v != fa[u]) dfs2(v, v);
    }
}
void add(int u, int v, int x) {
    int fu = top[u], fv = top[v];
    while(fu != fv) {
        if(dp[fu] < dp[fv]) swap(u, v), swap(fu, fv);
        update(dfn[fu], dfn[u], x, 1, 1, n);
        u = fa[fu];
        fu = top[u];
    }
    if(dfn[u] <= dfn[v]) update(dfn[u], dfn[v], x, 1, 1, n);
    else update(dfn[v], dfn[u], x, 1, 1, n);
}
int sum(int u, int v) {
    int ans = 0, fu = top[u], fv = top[v];
    while(fu != fv) {
        if(dp[fu] < dp[fv]) swap(u, v), swap(fu, fv);
        ans += query(dfn[fu], dfn[u], 1, 1, n);
        u = fa[fu];
        fu = top[u];
    }
    if(dfn[u] <= dfn[v]) ans += query(dfn[u], dfn[v], 1, 1, n);
    else ans += query(dfn[v], dfn[u], 1, 1, n);
    return ans;
}
int main() {
    scanf("%d", &n);
    for (int i = 2; i <= n; ++i) scanf("%d", &u), u++, g[u].pb(i);
    dfs1(1, 1);
    dfs2(1, 1);
    build(1, 1, n);
    scanf("%d", &q);
    for (int i = 1; i <= q; ++i){
        scanf("%s", s);
        scanf("%d", &u);
        ++u;
        if(s[0] == 'i') {
            printf("%d\n", dp[u] - sum(1, u));
            add(1, u, 1);
        }
        else {
            printf("%d\n", query(dfn[u], dfn[u]+sz[u]-1, 1, 1, n));
            update(dfn[u], dfn[u]+sz[u]-1, 0, 1, 1, n);
        }
    }
    return 0;
}
View Code

P2486 [SDOI2011]染色

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 3e5 + 5;
vector<int> g[N];
int  sz[N], fa[N], dp[N], son[N], top[N], dfn[N], to[N], cnt = 0;
int n, m, u, v, x;
int a[N];
char s[10];
struct node {
    int l, r, cnt, lazy;
}tree[N<<2];
void push_up(int rt) {
    tree[rt].cnt = tree[rt<<1].cnt + tree[rt<<1|1].cnt;
    if(tree[rt<<1].r == tree[rt<<1|1].l) tree[rt].cnt--;
    tree[rt].l = tree[rt<<1].l;
    tree[rt].r = tree[rt<<1|1].r;
}
void push_down(int rt) {
    tree[rt<<1] = tree[rt<<1|1] = {tree[rt].lazy, tree[rt].lazy, 1, tree[rt].lazy};
    tree[rt].lazy = 0;
}
node Merge(node a, node b) {
    node ans;
    if(!a.cnt) return b;
    else if(!b.cnt) return a;
    ans.l = a.l;
    ans.r = b.r;
    ans.cnt = a.cnt + b.cnt;
    if(a.r == b.l) ans.cnt--;
    return ans;
}
void build(int rt, int l, int r) {
    tree[rt].lazy = 0;
    if(l == r) {
        tree[rt].l = tree[rt].r = a[to[l]];
        tree[rt].cnt = 1;
        return ;
    }
    int m = l+r >> 1;
    build(ls);
    build(rs);
    push_up(rt);
}
void update(int L, int R, int x, int rt, int l, int r) {
    if(L <= l && r <= R) {
        tree[rt].lazy = tree[rt].l = tree[rt].r = x;
        tree[rt].cnt = 1;
        return ;
    }
    if(tree[rt].lazy) push_down(rt);
    int m = l+r >> 1;
    if(L <= m) update(L, R, x, ls);
    if(R > m) update(L, R, x, rs);
    push_up(rt);
}
node query(int L, int R, int rt, int l, int r) {
    if(L <= l && r <= R) return tree[rt];
    if(tree[rt].lazy) push_down(rt);
    int m = l+r >> 1;
    node ans = {0, 0, 0, 0};
    if(L <= m) ans = query(L, R, ls);
    if(R > m) ans = Merge(ans, query(L, R, rs));
    push_up(rt);
    return ans;
}
void add(int u, int v, int x) {
    int fu = top[u], fv = top[v];
    while(fu != fv) {
        if(dp[fu] < dp[fv]) swap(u, v), swap(fu, fv);
        update(dfn[fu], dfn[u], x, 1, 1, n);
        u = fa[fu];
        fu = top[u];
    }
    if(dfn[u] <= dfn[v]) update(dfn[u], dfn[v], x, 1, 1, n);
    else update(dfn[v], dfn[u], x, 1, 1, n);
}
int sum(int u, int v) {
    node l = {0, 0, 0, 0}, r = {0, 0, 0, 0};
    int fu = top[u], fv = top[v];
    while(fu != fv) {
        if(dp[fu] >= dp[fv]) {
            l = Merge(query(dfn[fu], dfn[u], 1, 1, n), l);
            u = fa[fu];
            fu = top[u];
        }
        else {
            r = Merge(query(dfn[fv], dfn[v], 1, 1, n), r);
            v = fa[fv];
            fv = top[v];
        }
    }
    if(dfn[u] <= dfn[v]) r = Merge(query(dfn[u], dfn[v], 1, 1, n), r);
    else l = Merge(query(dfn[v], dfn[u], 1, 1, n), l);
    swap(l.l, l.r);
    l = Merge(l, r);
    return l.cnt;
}
void dfs1(int u, int o) {
    dp[u] = dp[o] + 1;
    fa[u] = o;
    sz[u] = 1;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i];
        if(v != o) {
            dfs1(v, u);
            sz[u] += sz[v];
            if(sz[v] > sz[son[u]]) son[u] = v;
        }
    }
}
void dfs2(int u, int t) {
    top[u] = t;
    dfn[u] = ++cnt;
    to[cnt] = u;
    if(!son[u]) return ;
    dfs2(son[u], t);
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i];
        if(v != fa[u] && v != son[u]) dfs2(v, v);
    }
}
int main() {
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    for (int i = 1; i < n; ++i) scanf("%d %d", &u, &v), g[u].pb(v), g[v].pb(u);
    dfs1(1, 1);
    dfs2(1, 1);
    build(1, 1, n);
    for (int i = 1; i <= m; ++i) {
        scanf("%s", s);
        if(s[0] == 'Q') {
            scanf("%d %d", &u, &v);
            printf("%d\n", sum(u, v));
        }
        else {
            scanf("%d %d %d", &u, &v, &x);
            add(u, v, x);
        }
    }
    return 0;
}
View Code

HDU 3966

代码:

#pragma comment(linker,"/STACK:100000000,100000000")
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
#include
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 5e4 + 5;
struct edge {
    int to, nxt;
}edge[N*2];
int head[N], tot = 1;
int a[N], n, m, p, u, v, k;
int sz[N], dp[N], fa[N], son[N], dfn[N], top[N], to[N], cnt = 0;
int bit[N];
char s[10];
inline int read(){
   int s=0,w=1;
   char ch=getchar();
   while(ch<='0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void add(int u, int v) {
    edge[tot].to = v;
    edge[tot].nxt = head[u];
    head[u] = tot++;
}
void dfs1(int u, int o) {
    dp[u] = dp[o] + 1;
    sz[u] = 1;
    fa[u] = o;
    for (int i = head[u]; i; i = edge[i].nxt) {
        int v = edge[i].to;
        if(v != o) {
            dfs1(v, u);
            sz[u] += sz[v];
            if(sz[son[u]] < sz[v]) son[u] = v;
        }
    }
}
void dfs2(int u, int t) {
    top[u] = t;
    dfn[u] = ++cnt;
    to[cnt] = u;
    if(!son[u]) return ;
    dfs2(son[u], t);
    for (int i = head[u]; i; i = edge[i].nxt) {
        int v = edge[i].to;
        if(v != fa[u] && v != son[u]) dfs2(v, v);
    }
}
inline void update(int x, int a) {
    while(x <= n) bit[x] += a, x += x&-x;
}
inline int query(int x) {
    int ans = 0;
    while(x) ans += bit[x], x -= x&-x;
    return ans;
}
void add(int u, int v, int x) {
    int fu = top[u], fv = top[v];
    while(fu != fv) {
        if(dp[fu] < dp[fv]) swap(u, v), swap(fu, fv);
        update(dfn[fu], x);
        update(dfn[u]+1, -x);
        u = fa[fu];
        fu = top[u];
    }
    if(dfn[u] <= dfn[v]) update(dfn[u], x), update(dfn[v]+1, -x);
    else update(dfn[v], x), update(dfn[u]+1, -x);
}
int main() {
    while(~scanf("%d %d %d", &n, &m, &p)) {
        for (int i = 1; i <= n; ++i) a[i] = read();
        for (int i = 1; i <= m; ++i) u = read(), v = read(), add(u, v), add(v, u);
        cnt = 0;
        dp[1] = 1;
        dfs1(1, 1);
        dfs2(1, 1);
        for (int i = 1; i <= n; ++i) update(dfn[i], a[i]), update(dfn[i]+1, -a[i]);
        for (int i = 1; i <= p; ++i) {
            scanf("%s", s);
            if(s[0] == 'I') {
                u = read();
                v = read();
                k = read();
                add(u, v, k);
            }
            else if(s[0] == 'D') {
                u = read();
                v = read();
                k = read();
                add(u, v, -k);
            }
            else {
                u = read();
                printf("%d\n", query(dfn[u]));
            }
        }
        for (int i = 1; i <= n; ++i) head[i] = bit[i] = son[i] = 0;
        tot = 1;
    }
    return 0;
}
View Code

POJ 2763

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
#include
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 1e5 + 5;
struct edge {
    int to, id, nxt;
}edge[N*2];
int n, q, s, u, v, w[N], a[N], aa[N], op;
int head[N], tot = 1;
int fa[N], sz[N], dp[N], son[N], dfn[N], top[N], to[N], cnt = 0;
int tree[N<<2];
void add(int u, int v, int id) {
    edge[tot].to =v;
    edge[tot].id = id;
    edge[tot].nxt = head[u];
    head[u] = tot++;
}
void dfs1(int u, int o) {
    dp[u] = dp[o] + 1;
    fa[u] = o;
    sz[u] = 1;
    for (int i = head[u]; i; i = edge[i].nxt) {
        int v = edge[i].to;
        int id = edge[i].id;
        if(v != o) {
            a[v] = w[id];
            aa[id] = v;
            dfs1(v, u);
            sz[u] += sz[v];
            if(sz[son[u]] < sz[v]) son[u] = v;
        }
    }
}
void dfs2(int u, int t) {
    top[u] = t;
    dfn[u] = ++cnt;
    to[cnt] = u;
    if(!son[u]) return ;
    dfs2(son[u], t);
    for (int i = head[u]; i; i = edge[i].nxt) {
        int v = edge[i].to;
        if(v != fa[u] && v != son[u]) dfs2(v, v);
    }
}
void push_up(int rt) {
    tree[rt] = tree[rt<<1] + tree[rt<<1|1];
}
void update(int p, int v, int rt, int l, int r) {
    if(l == r) {
        tree[rt] += v;
        return ;
    }
    int m = l+r >> 1;
    if(p <= m) update(p, v, ls);
    else update(p, v, rs);
    push_up(rt);
}
int query(int L, int R, int rt, int l, int r) {
    if(L > R) return 0;
    if(L <= l && r <= R) return tree[rt];
    int m = l+r >> 1, ans = 0;
    if(L <= m) ans += query(L, R, ls);
    if(R > m) ans += query(L, R, rs);
    return ans;
}
void build(int rt, int l, int r) {
    if(l == r) {
        tree[rt] = a[to[l]];
        return ;
    }
    int m = l+r >> 1;
    build(ls);
    build(rs);
    push_up(rt);
}
int sum(int u, int v) {
    int ans = 0, fu = top[u], fv = top[v];
    while(fu != fv) {
        if(dp[fu] < dp[fv]) swap(u, v), swap(fu, fv);
        ans += query(dfn[fu], dfn[u], 1, 1, n);
        u = fa[fu];
        fu = top[u];
    }
    if(dfn[u] <= dfn[v]) ans += query(dfn[u]+1, dfn[v], 1, 1, n);
    else ans += query(dfn[v]+1, dfn[u], 1, 1, n);
    return ans;
}
int main() {
    scanf("%d %d %d", &n, &q, &s);
    for (int i = 1; i < n; ++i) scanf("%d %d %d", &u, &v, &w[i]), add(u, v, i), add(v, u, i);
    dfs1(1, 1);
    dfs2(1, 1);
    build(1, 1, n);
    while(q--) {
        scanf("%d", &op);
        if(op == 0) {
            scanf("%d", &u);
            printf("%d\n", sum(s, u));
            s = u;
        }
        else {
            scanf("%d %d", &u, &v);
            update(dfn[aa[u]], v-a[aa[u]], 1, 1, n);
            a[aa[u]] = v;
        }
    }
    return 0;
}
View Code

POJ 3237

代码: 

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include
#include
#include
#include
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 1e4 + 5;
vector g[N];
int T, n, u, v, w[N], a[N], aa[N];
char s[15];
int fa[N], sz[N], dp[N], son[N], dfn[N], top[N], to[N], cnt = 0;
struct node {
    int mx, mn, lazy;
}tree[N<<2];
void dfs1(int u, int o) {
    fa[u] = o;
    dp[u] = dp[o] + 1;
    sz[u] = 1;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        int id = g[u][i].se;
        if(v != o) {
            dfs1(v, u);
            sz[u] += sz[v];
            a[v] = w[id];
            aa[id] = v;
            if(sz[v] > sz[son[u]]) son[u] = v;
        }
    }
}
void dfs2(int u, int t) {
    top[u] = t;
    dfn[u] = ++cnt;
    to[cnt] = u;
    if(!son[u]) return ;
    dfs2(son[u], t);
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i].fi;
        if(v != fa[u] && v != son[u]) dfs2(v, v);
    }
}
void push_up(int rt) {
    tree[rt].mn = min(tree[rt<<1].mn, tree[rt<<1|1].mn);
    tree[rt].mx = max(tree[rt<<1].mx, tree[rt<<1|1].mx);
}
void push_down(int rt) {
    tree[rt<<1].mn = -tree[rt<<1].mn;
    tree[rt<<1].mx = -tree[rt<<1].mx;
    tree[rt<<1|1].mn = -tree[rt<<1|1].mn;
    tree[rt<<1|1].mx = -tree[rt<<1|1].mx;
    swap(tree[rt<<1].mn, tree[rt<<1].mx);
    swap(tree[rt<<1|1].mn, tree[rt<<1|1].mx);
    tree[rt<<1].lazy ^= 1;
    tree[rt<<1|1].lazy ^= 1;
    tree[rt].lazy = 0;
}
void build(int rt, int l, int r) {
    tree[rt].lazy = 0;
    if(l == r) {
        tree[rt].mn = tree[rt].mx = a[to[l]];
        return ;
    }
    int m = l+r >> 1;
    build(ls);
    build(rs);
    push_up(rt);
}
void update(int p, int v, int rt, int l, int r) {
    if(l == r) {
        tree[rt].mn = tree[rt].mx = v;
        return ;
    }
    if(tree[rt].lazy) push_down(rt);
    int m = l+r >> 1;
    if(p <= m) update(p, v, ls);
    else update(p, v, rs);
    push_up(rt);
}
void Update(int L, int R, int rt, int l, int r) {
    if(L > R) return ;
    if(L <= l && r <= R) {
        tree[rt].lazy ^= 1;
        tree[rt].mx = -tree[rt].mx;
        tree[rt].mn = -tree[rt].mn;
        swap(tree[rt].mx, tree[rt].mn);
        return ;
    }
    if(tree[rt].lazy) push_down(rt);
    int m = l+r >> 1;
    if(L <= m) Update(L, R, ls);
    if(R > m) Update(L, R, rs);
    push_up(rt);
}
int query(int L, int R, int rt, int l, int r) {
    if(L > R) return INT_MIN;
    if(L <= l && r <= R) return tree[rt].mx;
    if(tree[rt].lazy) push_down(rt);
    int m = l+r >> 1, ans = INT_MIN;
    if(L <= m) ans = max(ans, query(L, R, ls));
    if(R > m) ans = max(ans, query(L, R, rs));
    push_up(rt);
    return ans;
}
void change(int u, int v) {
    int fu = top[u], fv = top[v];
    while(fu != fv) {
        if(dp[fu] < dp[fv]) swap(u, v), swap(fu, fv);
        Update(dfn[fu], dfn[u], 1, 1, n);
        u = fa[fu];
        fu = top[u];
    }
    if(dfn[u] <= dfn[v]) Update(dfn[u]+1, dfn[v], 1, 1, n);
    else Update(dfn[v]+1, dfn[u], 1, 1, n);
}
int solve(int u , int v) {
    int ans = INT_MIN, fu = top[u], fv = top[v];
    while(fu != fv) {
        if(dp[fu] < dp[fv]) swap(u, v), swap(fu, fv);
        ans = max(ans, query(dfn[fu], dfn[u], 1, 1, n));
        u = fa[fu];
        fu = top[u];
    }
    if(dfn[u] <= dfn[v]) ans = max(ans, query(dfn[u]+1, dfn[v], 1, 1, n));
    else ans = max(ans, query(dfn[v]+1, dfn[u], 1, 1, n));
    return ans;
}
int main() {
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        for (int i = 1; i < n; ++i) scanf("%d %d %d", &u, &v, &w[i]), g[u].pb(mp(v, i)), g[v].pb(mp(u, i));
        dp[1] = 0;
        dfs1(1, 1);
        dfs2(1, 1);
        build(1, 1, n);
        while(true) {
            scanf("%s", s);
            if(s[0] == 'D') break;
            scanf("%d %d", &u, &v);
            if(s[0] == 'C') {
                update(dfn[aa[u]], v, 1, 1, n);
            }
            else if(s[0] == 'N') {
                change(u, v);
            }
            else {
                printf("%d\n", solve(u, v));
            }
        }
        cnt = 0;
        for (int i = 1; i <= n; ++i) g[i].clear(), son[i] = 0;
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/widsom/p/7920524.html

你可能感兴趣的:(算法笔记--树的直径 && 树形dp && 虚树 && 树分治 && 树上差分 && 树链剖分)