POJ 1987

T_T为毛会这样子,我的写就是过不了,。。。。。。。

其实这题不难,很容易想到吧,我一开始也想着用枚举这类方法,但复杂度实在不敢想,没想到,真的是用这种方法。。

今天学了一个叫树的重心,可以使分治的子树点数大致相等,降低了递归的层次吧。。。

嗯,这题的复杂度,怎么的也有o(n^2)以上,而且n=40000,竟然。。。。不敢细想了。。。。

代码复制:http://blog.csdn.net/acm_cxlove/article/details/9222999

我自己锉代码就算了T_T,搞不懂了。。。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int N = 40005;
struct Edge{
    int v,next,w;
}e[N<<1];
int tot,start[N],n,m,k,del[N],ans=0;
int size[N];
void _add(int u,int v,int w){
    e[tot].v=v;e[tot].w=w;
    e[tot].next=start[u];start[u]=tot++;
}
void add(int u,int v,int w){
    _add(u,v,w);
    _add(v,u,w);
}
void cal(int u,int pre){
    size[u]=1;
    for(int i=start[u];i!=-1;i=e[i].next){
        int v=e[i].v;
        if(v==pre||del[v]) continue;
        cal(v,u);
        size[u]+=size[v];
    }
}
int newroot,maxsize,totalsize;
void dfs(int u,int pre){
    int mx=0,sum=1;
    for(int i=start[u];i!=-1;i=e[i].next){
        int v=e[i].v;
        if(v==pre||del[v]) continue;
        dfs(v,u);
        mx=max(mx,size[v]);
        sum+=size[v];
    }
    mx=max(mx,totalsize-sum);
    if(mx<maxsize){
        maxsize=mx;
        newroot=u;
    }
}
int search(int r){
    newroot=-1;maxsize=1<<30;
    cal(r,-1);
    totalsize=size[r];
    dfs(r,-1);
    return newroot;
}
int dist[N],idx;
vector<int>sub[N],all;
void gao(int u,int pre){
    all.push_back(dist[u]);
    sub[idx].push_back(dist[u]);
    for(int i=start[u];i!=-1;i=e[i].next){
        int v=e[i].v,w=e[i].w;
        if(v==pre||del[v]) continue;
        dist[v]=dist[u]+w;
        gao(v,u);
    }
}
void solve(int root){
    root=search(root);
    del[root]=1;
    if(totalsize==1) return ;
    idx=0;all.clear();
    for(int i=start[root];i!=-1;i=e[i].next){
        int v=e[i].v,w=e[i].w;
        if(del[v]) continue;
        sub[idx].clear();
        dist[v]=w;
        gao(v,-1);
        sort(sub[idx].begin(),sub[idx].end());
        idx++;
    }
    for(int i=0;i<idx;i++){
        int pos;
        for(int j=0;j<sub[i].size();j++){
            pos=upper_bound(sub[i].begin(),sub[i].end(),k-sub[i][j])-sub[i].begin()-1;
            if(pos>j) ans-=pos-j;
        }
        pos=upper_bound(sub[i].begin(),sub[i].end(),k)-sub[i].begin()-1;
        if(pos>=0) ans+=pos+1;
    }
    sort(all.begin(),all.end());
    for(int i=0;i<all.size();i++){
        int pos=upper_bound(all.begin(),all.end(),k-all[i])-all.begin()-1;
        if(pos>i) ans+=pos-i;
    }
    for(int i=start[root];i!=-1;i=e[i].next){
        int v=e[i].v;
        if(del[v]) continue;
        solve(v);
    }
}
int main(){
    tot=0;memset(start,-1,sizeof(start));
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++){
        int u,v,w;char str[5];
        scanf("%d%d%d%s",&u,&v,&w,str);
        add(u,v,w);
    }
    scanf("%d",&k);
    solve(1);
    printf("%d\n",ans);
    return 0;
}

  

时间: 2024-08-07 21:19:23

POJ 1987的相关文章

POJ 1987 Distance Statistics (树上点分治)

题目地址:POJ 1987 点分治模板题,跟POJ 1741几乎一样,.. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map> #include <set> #include <stdi

POJ 1987 Distance Statistics 树分治

Distance Statistics Description Frustrated at the number of distance queries required to find a reasonable route for his cow marathon, FJ decides to ask queries from which he can learn more information. Specifically, he supplies an integer K (1 <= K

POJ - 1987 Distance Statistics 树上的分治

题目大意:和poj 1741的那题和类似,求树上节点之间的距离小于等于k的节点对有多少对 解题思路:具体可参考:<分治算法在树的路径问题中的应用--漆子超> 给这题的输入坑了,注意输入,不然会超时 #include<cstdio> #include<vector> #include<algorithm> using namespace std; #define maxn 40010 int vis[maxn], Sum[maxn], d[maxn], dp[

POJ 1987 BZOJ 3365 Distance Statistics 树的分治(点分治)

题目大意:(同poj1741,刷一赠一系列) CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 40010 #define INF 0x3f3f3f3f using namespace std; int points,edges,k; int head[MAX],total; int next[MAX <<

poj1741+poj1987+poj2114——点分治入门题集合

最近看了看点分治,从poj上找到几道题,都比较裸.而且感觉这三道题都长得差不多呀qwq ------------------------------------------------ [poj 1741]Tree 题意:给定一棵边带权的树,求两点之间的距离小于或等于K的点对个数. 找重心,相当于把无根树转变为有根树.再利用分治的思想(根据经过重心或不经过重心来划分). 对于在同一个子树的情况要单独拎出来算并减去它们(因为是不该算在内的呀qwq) 另外选取重心的好处是时间复杂度O(NlogN*l

[SinGuLaRiTy] 分治题目复习

[SInGuLaRiTy-1025] Copyrights (c) SinGuLaRiTy 2017. All Rights Reserved. [POJ 1905] 棍的扩张 (Expanding Rods) 题目描述 已知一根长为L的细棍被加热了n摄氏度,那么其新的长度为L'=(1+n*C)*L.中间的C是热膨胀系数.当一根细棍被夹在两面墙中间然后被加热,它会膨胀,其形状会变成一个弧,而原来的细棍(加热前的细棍)就是这个弧所对的弦.你的任务是计算出弧的中点与弦的中点的距离. 输入 包含多组数

POJ 1741/1987 树的点分治

树的点分治,主要思想是每次找子树的重心,计算经过根节点的情况数,再减去点对属于同一子树的情况. 1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 #include <string> 5 #include <string.h> 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <

POJ - 3186 Treats for the Cows (区间DP)

题目链接:http://poj.org/problem?id=3186 题意:给定一组序列,取n次,每次可以取序列最前面的数或最后面的数,第n次出来就乘n,然后求和的最大值. 题解:用dp[i][j]表示i~j区间和的最大值,然后根据这个状态可以从删前和删后转移过来,推出状态转移方程: dp[i][j]=max(dp[i+1][j]+value[i]*k,dp[i][j-1]+value[j]*k) 1 #include <iostream> 2 #include <algorithm&

POJ 2533 - Longest Ordered Subsequence(最长上升子序列) 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:http://poj.org/problem?id=2533 Description A numeric sequence of ai is ordered if a1 < a2 < ... < aN. Let the subsequence of the given numeric sequence (a1, a2, ..., aN) be any sequence (ai1, ai2, ..., aiK)