个人赛(三)

I题:

You are given n points on Cartesian plane. Every point is a lattice point (i. e. both of its coordinates are integers), and all points are distinct.

You may draw two straight lines (not necessarily distinct). Is it possible to do this in such a way that every point lies on at least one of these lines?

Input

The first line contains one integer n (1 ≤ n ≤ 105) — the number of points you are given.

Then n lines follow, each line containing two integers xi and yi (|xi|, |yi| ≤ 109)— coordinates of i-th point. All n points are distinct.

Output

If it is possible to draw two straight lines in such a way that each of given points belongs to at least one of these lines, print YES. Otherwise, print NO.

Examples

Input

5
0 0
0 1
1 1
1 -1
2 2

Output

YES

Input

5
0 0
1 0
2 1
1 1
2 3

Output

NO

Note

In the first example it is possible to draw two lines, the one containing the points 1, 3 and 5, and another one containing two remaining points.

题意:给你n个点,画两条直线(可能相同),要你判断这n个点是否都在这两条直线中的一条或两条上

分析:首先呢可以选前三个点得出三条直线(或者三点共线时只有一条,但这条一定是题目中要画的一条直线),这三条直线中一定有一条或两条是最终所求直线,然后判断其余的点分布情况

1,确定一条直线后,在判断点是否在其上面,若有一个或两个点不在上面,满足条件 

2,若有三个及以上的点都不在那条直线上,在判断这几个点能否都在一条直线上,不能就不能满足条件,否则可以

关键就是要先确定一条直线。。。。。 

AC code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+3;
bool yes[maxn];
typedef long long ll;
struct Point{
ll x,y;
}p[maxn];
int n;
bool judge(const Point& a,const Point& b,const Point& c)
{
    return (a.x-b.x)*(b.y-c.y)==(a.y-b.y)*(b.x-c.x);///判断是否共线
}
bool check(int a,int b)
{
    memset(yes,0,sizeof yes);
    for(int i=1;i<=n;i++)
        if(judge(p[a],p[b],p[i]))///求出与第一条直线共线的点,剩下的就是不共线的点
           yes[i]=1;
    int first=0,second=0;///找出是否有两个点及以上与第一条直线不共线的点
    for(int i=1;i<=n;i++)
    if(!yes[i]){
        if(!first) first=i;
        else second=i;
    }
    if(!first||!second)///如果只有一个或没有点与第一条直线不共线,肯定满足条件
      return true;
    for(int i=1;i<=n;i++)
        if(!yes[i]&&!judge(p[first],p[second],p[i])) return false;///如果与第一条直线不共线 
                                           ///的点中存在三个点也互不共线,那肯定不满足条件
    return true;///如果不存在上述三个点,就满足条件
}
int main()
{
    ios::sync_with_stdio(0),cin.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>p[i].x>>p[i].y;
    if(n<=4) cout<<"YES"<<endl;
    else{
    if(check(1,2)||check(1,3)||check(2,3))///前三个点确定三种情况,分别都确定一条直线
        cout<<"YES"<<endl;
    else
        cout<<"NO"<<endl;
    }
    return 0;
}

 B题:

JGShining's kingdom consists of 2n(n is no more than 500,000) small cities which are located in two parallel lines. 

Half of these cities are rich in resource (we call them rich cities) while the others are short of resource (we call them poor cities). Each poor city is short of exactly one kind of resource and also each rich city is rich in exactly one kind of resource. You may assume no two poor cities are short of one same kind of resource and no two rich cities are rich in one same kind of resource. 

With the development of industry, poor cities wanna import resource from rich ones. The roads existed are so small that they're unable to ensure the heavy trucks, so new roads should be built. The poor cities strongly BS each other, so are the rich ones. Poor cities don't wanna build a road with other poor ones, and rich ones also can't abide sharing an end of road with other rich ones. Because of economic benefit, any rich city will be willing to export resource to any poor one. 

Rich citis marked from 1 to n are located in Line I and poor ones marked from 1 to n are located in Line II. 

The location of Rich City 1 is on the left of all other cities, Rich City 2 is on the left of all other cities excluding Rich City 1, Rich City 3 is on the right of Rich City 1 and Rich City 2 but on the left of all other cities ... And so as the poor ones. 

But as you know, two crossed roads may cause a lot of traffic accident so JGShining has established a law to forbid constructing crossed roads. 

For example, the roads in Figure I are forbidden. 



In order to build as many roads as possible, the young and handsome king of the kingdom - JGShining needs your help, please help him. ^_^ 

Input

Each test case will begin with a line containing an integer n(1 ≤ n ≤ 500,000). Then n lines follow. Each line contains two integers p and r which represents that Poor City p needs to import resources from Rich City r. Process to the end of file. 

Output

For each test case, output the result in the form of sample. 
You should tell JGShining what's the maximal number of road(s) can be built. 

Sample Input

2
1 2
2 1
3
1 2
2 3
3 1

Sample Output

Case 1:
My king, at most 1 road can be built.

Case 2:
My king, at most 2 roads can be built.

题意:有两排点,上面是从1—n,下面也是从1—n,并且给出上面和下面的点的连接情况,要保证连接的线不交叉最多可以连几条(不可以转弯连哦)

分析:把这两排点看成一个单射函数,上面是定义域,下面是值域,上面要递增排列,所以连线时下面也要递增排列(非严格递增),故要求下面的非下降子序列,由于n是1e5级别的,故只能用O(nlogn)的算法

AC code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+3;
int g[maxn];
int main()
{
    int n;
    int a,b;
    int f[maxn];
    int cas=0;
    while(~scanf("%d",&n)){
    for(int i=1;i<=n;i++){
       scanf("%d%d",&a,&b);
       f[a]=b;///f[x]为单射递增函数,x递增,f[x]也递增,故要求最长上升子序列
    }
    int k=0;
    memset(g,0,sizeof g);///由于要二分,这里手写队列
    for(int i=1;i<=n;i++)
      if(k==0)
         g[++k]=f[i];///队列为空时
      else
      {
          if(g[k]<f[i])///当要加入的元素大于队尾元素时,直接加入
             g[++k]=f[i];
          else///否则找队列中第一次出现比f[i]大的数,并将它替换,这样替换可以保证前面更小
          {   ///用二分找,复杂度logn
              int l=0,r=k;
              while(l<=r)///二分找第一个大于key的值
              {
                  int mid=(l+r)>>1;
                  if(g[mid]<=f[i])
                      l=mid+1;
                  else if(g[mid]>f[i])
                      r=mid-1;
              }
              g[l]=f[i];
          }
      }
      cas++;
      printf("Case %d:\n",cas);
      if(k==1) printf("My king, at most 1 road can be built.\n\n");///单复数注意
      else printf("My king, at most %d roads can be built.\n\n",k);
    }
    return 0;
}

  最后还贴个O(n^2)求LIS的板子:

int LIS(int A[],int n)
{
    int* d = new int[n];
    int len = 1;
    int i,j;
    for(i=0;i<n;i++)
    {
        d[i]=1;
        for(j=0;j<i;j++)
        {
            if(A[j]<=A[i] && (d[j]+1)>=d[i])
                d[i]=d[j]+1;
        }
        if(d[i]>len) len=d[i];
    }
    delete []d;
    return len;
}

就是每次都求以A[i]结尾的序列,如果满足A[i]>=A[j](j<i)  dp[i]=max(dp[i],dp[j]+1)  

每次都求一下dp[i]的最大值

C题:

糟糕的事情发生啦,现在大家都忙着逃命。但是逃命的通道很窄,大家只能排成一行。 

现在有n个人,从1标号到n。同时有一些奇怪的约束条件,每个都形如:a必须在b之前。 
同时,社会是不平等的,这些人有的穷有的富。1号最富,2号第二富,以此类推。有钱人就贿赂负责人,所以他们有一些好处。 

负责人现在可以安排大家排队的顺序,由于收了好处,所以他要让1号尽量靠前,如果此时还有多种情况,就再让2号尽量靠前,如果还有多种情况,就让3号尽量靠前,以此类推。 

那么你就要安排大家的顺序。我们保证一定有解。

Input

第一行一个整数T(1 <= T <= 5),表示测试数据的个数。 
然后对于每个测试数据,第一行有两个整数n(1 <= n <= 30000)和m(1 <= m <= 100000),分别表示人数和约束的个数。 

然后m行,每行两个整数a和b,表示有一个约束a号必须在b号之前。a和b必然不同。

Output

对每个测试数据,输出一行排队的顺序,用空格隔开。

Sample Input

1
5 10
3 5
1 4
2 5
1 2
3 4
1 4
2 3
1 5
3 5
1 2

Sample Output

1 2 3 4 5

分析:是一个拓扑排序,但要注意要反向拓扑,为什么呢,你看,假设有四个人,3在1前,2在4前,这时正向的话用优先队列从小到大排序,会造成2在1前面,故要反向拓扑,我说的有道理吗,哈哈哈

拓扑排序的实现步骤

  1. 在有向图中选一个没有前驱(入度为0)的顶点并且输出
  2. 从图中删除该顶点和所有以它为尾的弧(白话就是:删除所有和它有关的边)
  3. 重复上述两步,直至所有顶点输出,或者当前图中不存在无前驱的顶点为止,后者代表我们的有向图是有环的,因此,也可以通过拓扑排序来判断一个图是否有环。

AC code:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<set>
#include<queue>
#include<cstdio>
using namespace std;
typedef long long ll;
priority_queue<int,vector<int>,less<int> >q;
const int maxn=30005;
vector<int> edge[maxn];
int in[maxn];
int main()
{
    int t;
    int n,m;
    scanf("%d",&t);
    int a,b;
    while(t--){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        edge[i].clear();
        in[i]=0;
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&a,&b);
        in[a]++;
        edge[b].push_back(a);///反向存储,表示b->a,b要排在a前
    }
    for(int i=1;i<=n;i++)
    {
        if(in[i]==0)
            q.push(i);///优先队列默认从大到小排序
    }
    vector<int> ans;
    while(!q.empty())
    {
        int a=q.top();
        ans.push_back(a);
        q.pop();
        for(int i=0;i<edge[a].size();i++){
            int b=edge[a][i];
            in[b]--;///与之有关的节点入度都要减一
            if(in[b]==0)
                q.push(b);
        }
    }
    for(int i=ans.size()-1;i>=0;i--)///逆序输出
        printf("%d%c",ans[i],i==0?'\n':' ');
    }
    return 0;
}

总结:如果从小到大排,一般逆向拓扑,反之正向拓扑

E题:

Mad scientist Mike has constructed a rooted tree, which consists of n vertices. Each vertex is a reservoir which can be either empty or filled with water.

The vertices of the tree are numbered from 1 to n with the root at vertex 1. For each vertex, the reservoirs of its children are located below the reservoir of this vertex, and the vertex is connected with each of the children by a pipe through which water can flow downwards.

Mike wants to do the following operations with the tree:

  1. Fill vertex v with water. Then v and all its children are filled with water.
  2. Empty vertex v. Then v and all its ancestors are emptied.
  3. Determine whether vertex v is filled with water at the moment.

Initially all vertices of the tree are empty.

Mike has already compiled a full list of operations that he wants to perform in order. Before experimenting with the tree Mike decided to run the list through a simulation. Help Mike determine what results will he get after performing all the operations.

Input

The first line of the input contains an integer n (1 ≤ n ≤ 500000) — the number of vertices in the tree. Each of the following n - 1 lines contains two space-separated numbers aibi (1 ≤ ai, bi ≤ nai ≠ bi) — the edges of the tree.

The next line contains a number q (1 ≤ q ≤ 500000) — the number of operations to perform. Each of the following q lines contains two space-separated numbers ci (1 ≤ ci ≤ 3), vi (1 ≤ vi ≤ n), where ci is the operation type (according to the numbering given in the statement), and vi is the vertex on which the operation is performed.

It is guaranteed that the given graph is a tree.

Output

For each type 3 operation print 1 on a separate line if the vertex is full, and 0 if the vertex is empty. Print the answers to queries in the order in which the queries are given in the input.

Examples

Input

5
1 2
5 1
2 3
4 2
12
1 1
2 3
3 1
3 2
3 3
3 4
1 2
2 4
3 1
3 3
3 4
3 5

Output

0
0
0
1
0
1
0
1

题意:

给一棵树,多次操作,每次对于节点 v 有三种操作: 

  • 操作1:将以 v 为根的子树全都赋值为 1
  • 操作2:将 v 以及它所有祖先都赋值为 0
  • 操作3:询问 v 的值(1或者0) 
  • 我们可以发现这棵树有这几个性质: 
    • 若节点 v 为根的子树中存在 0,那么 v 肯定为 0
    • 若节点 v 为 1,那么以它为根的的子树中的节点肯定都是 1
  • 于是我们就可以维护一下深搜序的区间和,深搜序让我们可以很快地知道某棵子树的信息
  • 这样每个操作就能变成这样: 

    关键是dfs给树的节点编号

    Ac code:

    • 1:若子树v存在 0 节点 则把v的父亲更新成0。然后把 v 的子树全都更新成1
    • 2:把节点 v 更新成0
    • 3:询问以 v 为根的子树内是否有0节点,没有则表示1
    #include<iostream>
    #include<cstdio>
    #include<vector>
    using namespace std;
    #define lson (rt<<1)
    #define rson (rt<<1|1)
    const int maxn=5e5+1;
    int parent[maxn];
    struct Tree{
    int val,lazy;
    int l,r;
    }tree[maxn<<2];
    bool flag;
    void pushup(int rt)
    {
        if(tree[lson].val&tree[rson].val) tree[rt].val=1;///如果两个儿子都为1,父亲才为1
        else tree[rt].val=0;                             ///有一个为0(没水),说明父亲也没水
    }
    void pushdown(int rt)
    {
        if(tree[rt].lazy)
        {
            tree[lson].val=tree[rson].val=1;
            tree[lson].lazy=tree[rson].lazy=1;
            tree[rt].lazy=0;
        }
    }
    void build(int l,int r,int rt)
    {
        if(l==r)
        {
            tree[rt].val=0;
            tree[rt].lazy=0;
            return;
        }
        int mid=(l+r)>>1;
        build(l,mid,lson);
        build(mid+1,r,rson);
        pushup(rt);
    }
    void update(int L,int R,int l,int r,int rt,int val)
    {
        if(L<=l&&r<=R)
        {
            if(tree[rt].val==0) flag=1;
            tree[rt].val=val;
            if(val) tree[rt].lazy=1;
            return;
        }
        pushdown(rt);
        int mid=(l+r)>>1;
        if(L<=mid) update(L,R,l,mid,lson,val);
        if(R>mid) update(L,R,mid+1,r,rson,val);
        pushup(rt);
    }
    void query(int L,int R,int l,int r,int rt)
    {
        if(L<=l&&r<=R)
        {
            if(tree[rt].val==0) flag=1;
            return;
        }
        pushdown(rt);
        int mid=(l+r)>>1;
        if(L<=mid) query(L,R,l,mid,lson);
        if(R>mid) query(L,R,mid+1,r,rson);
    }
    vector<int>edge[maxn];
    int cnt;
    int L[maxn],R[maxn];
    ///用dfs给树的点编号
    void dfs(int rt,int pre)
    {
        L[rt]=++cnt;///左端点肯定是自己的编号
        for(int i=0;i<edge[rt].size();i++)
        {
            int v=edge[rt][i];
            if(v!=pre)
            {
                parent[v]=rt;///记录v的父亲节点
                dfs(v,rt);
            }
        }
        R[rt]=cnt;///右端点是它的子树一些其他节点的编号
    }
    int main()
    {
        int n;
        scanf("%d",&n);
        int a,b;
        for(int i=1;i<n;i++){
            scanf("%d%d",&a,&b);
            edge[a].push_back(b);
            edge[b].push_back(a);
        }
        parent[1]=1;
        cnt=0;
        dfs(1,0);
        build(1,n,1);
        int m,op;
        scanf("%d",&m);
        while(m--)
        {
            scanf("%d%d",&op,&a);
            if(op==1)
            {
                flag=0;
                update(L[a],R[a],1,n,1,1);///a为根的子树都要更新为1
                              ///趁遍历子树时若发现子树有节点为0的
                if(flag&&a!=1)///由于1号节点相当于无父亲节点了,所以不用更新
                     update(L[parent[a]],L[parent[a]],1,n,1,0);///如果儿子节点有为0的,a的父亲 
                                                              ///节点也要更新为0,
                                                       ///从而保证保证a以上的节点都是没水的
            }
            else if(op==2)
            {
                update(L[a],L[a],1,n,1,0);///单点更新,只更新a所在的的位置,相当于延迟0的上推
            }                             ///当询问到a以上的节点时,由于a所在位置为0(没水),
                                          ///那么a以上的节点肯定没水
            else
            {
                flag=0;
                query(L[a],R[a],1,n,1);
                if(flag) printf("0\n");///节点a为根所在的子树中若有一个为0,则点a所在的值为0
                else printf("1\n");
            }
        }
        return 0;
    }
    
     

F题:

给定一棵包含N个节点的树,节点编号1~N。  

请你对于每一个节点,计算它到所有其他节点的距离之和。(每条边的长度为1)

Input

第一行包含一个整数N。  

以下N-1行,每行包含两个整数a和b,代表ab之间有一条边。  

对于30%的数据,1 ≤ N ≤ 1000  

对于100%的数据,1 ≤ N ≤ 100000

Output

输出N行,依次对于1~N号节点输出答案。

Sample Input

4  
1 2  
2 3  
2 4

Sample Output

5  
3  
5  
5

分析:树上的dfs

不妨设根是1号节点。

一遍DFS可以求出来 1) 1号节点的权重W1 2)以每个节点为根的子树包含的节点数量,记作cnt[i]

假设有一个点P是1号节点的儿子。那么WP = W1 - cnt[P] + n - cnt[P]。因为把"中心"从1移动到P,以P为根的子树中的节点(一共cnt[P]个)距离都减少1,其余节点(一共n-cnt[P]个)距离都增加1。

所以再DFS一遍可以把其他的节点的权重都求出来。

AC code:

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
const int maxn=1e5+5;
vector<int>edge[maxn];
bool vis[maxn];
int res;
int cnt[maxn]={0};
int ans[maxn];
int n;
int son[maxn];
void dfs(int root,int pre)
{
    cnt[root]=1;

    for(int i=0;i<edge[root].size();i++)
    {
        int v=edge[root][i];
        if(v==pre) continue;
        dfs(v,root);
        cnt[root]+=cnt[v];///父亲节点的为根的节点数加上它儿子节点为根的子树的节点数
        son[root]+=son[v]+cnt[v];///son[v]表示以v为根节点的子树内部的路的总长度和
                                 ///cnt[v]表示以v为根节点的子树的总节点数,这个式子相当于把v为根节点的子树看成一个整体
                                ///到root的总长度=内部路径长度+子树节点数*1(当成整体后所有节点到root都为1)
    }
    return;
}
void dfs1(int now,int pre)
{
    for(int i=0;i<edge[now].size();i++){
       if(edge[now][i]==pre) continue;
        int v=edge[now][i];
        ans[v]=ans[now]-cnt[v]+n-cnt[v];
        dfs1(v,now);
    }
}
int main()
{
    cin>>n;
    int a,b;
    for(int i=1;i<=n-1;i++)
    {
        cin>>a>>b;
        edge[a].push_back(b);
        edge[b].push_back(a);
    }
    memset(son,0,sizeof son);
    dfs(1,0);
    for(int i=1;i<=n;i++)
        cout<<son[i]<<endl;
    ans[1]=son[1];
    dfs1(1,0);
    for(int i=1;i<=n;i++)
        cout<<ans[i]<<endl;
    return 0;
}

总结:所以以后树上计算一个点到其余节点路程和可以维护son和cnt两个数组

 同时还贴一份之前的暴搜代码,显然被T了(时间复杂度都没想就开暴搜QWQ)

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
const int maxn=1e5+5;
vector<int>edge[maxn];
int res;
void dfs(int root,int sum,int pre)
{
    res+=sum;
    for(int i=0;i<edge[root].size();i++){
        int v=edge[root][i];
        if(v==pre) continue;
        dfs(v,sum+1,root);
    }
}
int main()
{
    int n;
    cin>>n;
    int a,b;
    for(int i=1;i<=n-1;i++)
    {
        cin>>a>>b;
        edge[a].push_back(b);
        edge[b].push_back(a);
    }

    for(int i=1;i<=n;i++)
    {
        res=0;
        dfs(i,0,0);
        cout<<res<<endl;
    }
}

G题:

You are an experienced Codeforces user. Today you found out that during your activity on Codeforces you have made y submissions, out of which x have been successful. Thus, your current success rate on Codeforces is equal to x / y.

Your favorite rational number in the [0;1] range is p / q. Now you wonder: what is the smallest number of submissions you have to make if you want your success rate to be p / q?

Input

The first line contains a single integer t (1 ≤ t ≤ 1000) — the number of test cases.

Each of the next t lines contains four integers xyp and q (0 ≤ x ≤ y ≤ 109; 0 ≤ p ≤ q ≤ 109; y > 0; q > 0).

It is guaranteed that p / q is an irreducible fraction.

Hacks. For hacks, an additional constraint of t ≤ 5 must be met.

Output

For each test case, output a single integer equal to the smallest number of submissions you have to make if you want your success rate to be equal to your favorite rational number, or -1 if this is impossible to achieve.

Example

Input

4
3 10 1 2
7 14 3 8
20 70 2 7
5 6 1 1

Output

4
10
0
-1

题意(转)

记 AC 率为当前 AC 提交的数量 x / 总提交量 y 。已知最喜欢的 AC 率为 p/q (pq∈[0,1]pq∈[0,1]) 。 求最少在提交多少题(AC or NOT)能恰好达到 AC 率为 p/q 。

解题思路

记 P/Q 为 p/q 的最简比(P 与 Q 互质)。

问题可以转化为求最小的 n 满足 nPnQ=x+ay+bnPnQ=x+ay+b ,其中 a 为新提交的 AC 题数,b 为新提交的题数。

由于 nPnP , nQnQ, x+ax+a, y+by+b 都为整数,故可将等式化为 nP=x+anP=x+a 且 nQ=y+bnQ=y+b ,两个方程三个未知数,故该方程若有解即多解。求最小的 n 。同时,可以考虑到存在额外的条件:0≤(a=nP−x)≤(b=nQ−y)0≤(a=nP−x)≤(b=nQ−y) ,化简可得到 n≥⌈xP⌉n≥⌈xP⌉ 且 n≥⌈y−xQ−P⌉n≥⌈y−xQ−P⌉ ,求两者的最大值即为满足条件的最小的 n。此题求最少的新提交题数,ans=b=nQ−yans=b=nQ−y 。

同时,需注意特殊点:p=q 或 p=0 的情况。

AC code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=500000;
int main()
{
    ios::sync_with_stdio(0),cin.tie(0);
    ll x,y,p,q;
    int t;
    cin>>t;
    while(t--)
    {
        cin>>x>>y>>p>>q;
        if(p==0)
        {
            if(x==0)
                cout<<0<<endl;
            else
                cout<<-1<<endl;
            continue;
        }
        if(p==q)
        {
           if(x==y)
            cout<<0<<endl;
           else
            cout<<-1<<endl;
           continue;
        }
        ll n=max(ceil(1.0*(y-x)/(q-p)),ceil(1.0*x/p));
        ll ans=n*q-y;
        cout<<ans<<endl;
    }
    return 0;
}

 总结:上了大学后果然数学变差了QWQ....

H题:

There are n cities and n - 1 roads in the Seven Kingdoms, each road connects two cities and we can reach any city from any other by the roads.

Theon and Yara Greyjoy are on a horse in the first city, they are starting traveling through the roads. But the weather is foggy, so they can’t see where the horse brings them. When the horse reaches a city (including the first one), it goes to one of the cities connected to the current city. But it is a strange horse, it only goes to cities in which they weren't before. In each such city, the horse goes with equal probabilities and it stops when there are no such cities.

Let the length of each road be 1. The journey starts in the city 1. What is the expected length (expected value of length) of their journey? You can read about expected (average) value by the link https://en.wikipedia.org/wiki/Expected_value.

Input

The first line contains a single integer n (1 ≤ n ≤ 100000) — number of cities.

Then n - 1 lines follow. The i-th line of these lines contains two integers ui and vi(1 ≤ ui, vi ≤ nui ≠ vi) — the cities connected by the i-th road.

It is guaranteed that one can reach any city from any other by the roads.

Output

Print a number — the expected length of their journey. The journey starts in the city 1.

Your answer will be considered correct if its absolute or relative error does not exceed 10 - 6.

Namely: let's assume that your answer is a, and the answer of the jury is b. The checker program will consider your answer correct, if .

Examples

Input

4
1 2
1 3
2 4

Output

1.500000000000000

Input

5
1 2
1 3
3 4
2 5

Output

2.000000000000000

Note

In the first sample, their journey may end in cities 3 or 4 with equal probability. The distance to city 3 is 1 and to city 4 is 2, so the expected length is 1.5.

In the second sample, their journey may end in city 4 or 5. The distance to the both cities is 2, so the expected length is 2.

分析:求期望,就是每个节点的概率乘以它到1号节点的长度,直接用dfs就好了

最初还居然用的并查集。。。。。

ACcode;

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<cstdio>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
vector<int>v[maxn];
double res;
bool vis[maxn];
void dfs(int x,double y,int d)
{
    if(v[x].size()==1&&x!=1)
    {
        res+=y*d;
        return;
    }
    int s=v[x].size();
    for(int i=0;i<v[x].size();i++)
     if(!vis[v[x][i]]){
         vis[v[x][i]]=1;
        if(x==1)
         dfs(v[x][i],1.0*y/s,d+1);
        else
         dfs(v[x][i],1.0*y/(s-1),d+1);
     }
}
int main()
{
    int n;
    cin>>n;
    int x,y;
    for(int i=1;i<=n-1;i++)
    {
        cin>>x>>y;
        v[x].push_back(y);
        v[y].push_back(x);
    }
    memset(vis,0,sizeof vis);
    vis[1]=1;
    res=0;
    dfs(1,1,0);
    cout<<fixed<<setprecision(15)<<res<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/shaohang_/article/details/81638910
今日推荐