http://vjudge.net/contest/132620#overview
http://blog.csdn.net/acm_cxlove/article/details/7724021
简单题:A.E(注意细节).H.E.K
区间贪心:B.H.J
思路贪心:D.F.G.I.J
复杂的贪心:C(没做出来).L(没做出来).M(没做出来)
A.
题意:你有m磅猫粮,猫在n个房间里有你喜欢吃的东西。 下面n行分别表示你吃的有多少J[i],你需要用多少猫粮换这些吃的F[i]。你可以用F[i] * a% ,换取J[i] *a%.问你最多能换都少你喜欢吃的东西。
解析:按照J[i] / F[i] 排序即可。因为F[i]可以是0.所以要特殊处理零的情况
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>
#include <algorithm>
#include <list>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
using namespace std;
struct T
{
int j,f;
double w;
bool operator < (const T x)const
{
return w > x.w;
}
}a[1005];
int main()
{
//freopen("in.txt","r",stdin);
int m,n;
while(1)
{
double ans = 0;
scanf("%d%d",&m,&n);
if(m == -1 && n == -1)
{
break;
}
for(int i = 0; i < n; i ++)
{
scanf("%d%d",&a[i].j,&a[i].f);
if(a[i].f == 0)
{
a[i].w = 0;
ans += a[i].j;
}
else
a[i].w = 1.0 * a[i].j / a[i].f;
}
sort(a,a + n);
int temp;
int i = 0;
while(m != 0 && i < n)
{
if(a[i].w <= 0)
break;
temp = min(m,a[i].f);
ans = ans + temp * a[i].w;
m -= temp;
i ++;
}
printf("%.3f\n",ans);
}
return 0;
}
B.
题意:搬桌子,当你将桌子从一个位置搬到另一个位置时你要把整个过道的区间全占上,未被占用的过道可以同时搬桌子,搬一个桌子1个时间。给你n个桌子要从哪儿搬到哪儿,问最少的时间
解析:其实本质上是区间贪心,每次选择尽量多的不想交区间,求至少要选择几次。
先按照r从小到大排序,再按照l从大到小排序
代码:
//需要注意由于题目中是将卓子从一个位置移到另一个位置,所以l,r的大小是不一定的
#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>
#include <algorithm>
#include <list>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
using namespace std;
struct node
{
int l,r;
bool operator < (const node x)const
{
if(l == x.l)
return r < x.r;
return l < x.l;
}
} a[205];
bool vis[205];
int main()
{
// freopen("in.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
memset(vis,false,sizeof(vis));
int n;
scanf("%d",&n);
for(int i = 0; i < n; i ++)
{
scanf("%d%d",&a[i].l,&a[i].r);
if(a[i].l > a[i].r)
swap(a[i].l,a[i].r);
if(a[i].l % 2 == 0)
a[i].l --;
if(a[i].r % 2 == 0)
a[i].r --;
}
sort(a,a + n);
int bg,ans =0;
bool flag;
while(1)
{
ans ++;
bg = -1;
for(int i = 0; i < n; i ++)
{
if(vis[i] == false && a[i].l > bg)
{
bg = a[i].r;
vis[i] = true;
}
}
flag = false;
for(int i = 0; i < n; i ++)
{
if(vis[i] == false)
{
flag = true;
break;
}
}
if(flag == false)
break;
}
printf("%d\n",ans * 10);
}
return 0;
}
C.
题意:六种物品分别为1*1,2*2,3*3,4*4,5*5,6*6大小,每种物品不能改变,将他们都装在6*6的包裹中,至少要装多少个包裹。
解析:分物品讨论
6*6 包裹+1
5*5 包裹 + 1,1 的个数减11
4*4 包裹 + 1 , 2的个数 - 5,如果不够减max(cnt2 - 5 , 0)且要额外:cnt1 -(5 - cnt2) * 4,且与0求max
3*3 包裹 + (cnt3 + 3) / 4
if(cnt3 % 4 == 0) nothing
if(cnt3 % 4 == 1) ,2的个数- 5,1的个数 - 7如果不够减max(cnt2 - 5 , 0)且要额外:cnt1 -(27 - cnt2 * 4),且与0求max
if(cnt3 % 4 == 2), 2的个数-3,1的个数-7 如果不够减max(cnt2 - 3 , 0)且要额外:cnt1 -(18 - cnt2 * 4),且与0求max
if(cnt3 % 4 == 3), 2的个数-1,1的个数-5 如果不够减max(cnt2 - 1 , 0)且要额外:cnt1 -(9- cnt2 * 4),且与0求max
2*2 包裹 + (cnt2 + 8)/9
if(cnt2 % 9 == 0) nothing
else cnt1 - (36 - 4 * cnt2)与0求max
1*1 包裹 + (cnt1 + 35) / 36
代码:
//对细节的处理
#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>
#include <algorithm>
#include <list>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
using namespace std;
int main()
{
// freopen("in.txt","r",stdin);
//freopen("in2.txt","r",stdin);
// freopen("out.txt","w",stdout);
int a[10];
while(1)
{
int ans = 0;
bool flag = false;
for(int i = 1; i <= 6; i ++)
{
scanf("%d",&a[i]);
if(i == 6 || i == 5 || i == 4 )
ans += a[i];
if(a[i] != 0)
flag = true;
}
if(flag == false)
{
break;
}
a[1] = max(0,a[1] - 11 * a[5]);
int num;
if(a[2] < a[4] * 5)
a[1] = max(0,a[1] - (5 * a[4] - a[2]) * 4);
a[2] = max(0,a[2] -a[4] * 5);
ans += (a[3] + 3) / 4;
a[3] = a[3] % 4;
if(a[3] == 3)
{
num = 1;
if(num > a[2])
{
a[1] = max(0,a[1] - (9 - 4 * a[2]));
}
else
{
a[1] = max(0,a[1] - 5);
}
a[2] = max(0,a[2] - num);
}
else if(a[3] == 2)
{
num = 3;
if(num > a[2])
{
a[1] = max(0,a[1] - (18 - 4 * a[2]));
}
else
{
a[1] = max(0,a[1] - 6);
}
a[2] = max(0,a[2] - num);
}
else if(a[3] == 1)
{
num = 5;
if(num > a[2])
{
a[1] = max(0,a[1] - (27 - 4 * a[2]));
}
else
{
a[1] = max(0,a[1] - 7);
}
a[2] = max(0,a[2] - num);
}
ans += (a[2] + 8) / 9;
a[2] = a[2] % 9;
//特别注意此处是当且仅当有2个的剩余时才会加
if(a[2])a[1] =max(0,a[1] - (36 - a[2] * 4 ));
ans += (a[1] + 35) / 36;
printf("%d\n",ans);
}
return 0;
}
D.m只牛,每只牛的位置为p[i],任意两只牛通信要耗费fabs(p[i] - p[j]),如果让每头牛之间都能通信,所需要耗费的价值 * 2
分析:先对牛的位置进行排序,位置排在最前面的,算fabs时都是按照负数计算。
假设牛1和牛5通信,牛一对结果的贡献已经计算一次了。后面牛5对牛一通信,牛1和牛5产生的贡献还会再计算一次。
可以计算牛一和其他所有牛通信对结果的贡献,遍历,并将最后的结果*2。因为每头牛的位置都是不同的,当前位置与排在它前面的通信,贡献正值,当前位置与排在它后面的通信则贡献负值
代码:
//单个不会超但乘n就超了。一定要用long long
#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>
#include <algorithm>
#include <list>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
using namespace std;
long long a[10005];
int main()
{
//freopen("in.txt","r",stdin);
int n;
scanf("%d",&n);
for(int i= 0; i < n; i ++)
{
scanf("%I64d",&a[i]);
}
sort(a,a + n);
long long ans= 0;
for(int i = 0; i < n; i ++)
{
ans += -(n - 1 - i) * a[i] + i * a[i];
}
ans = ans * 2;
printf("%I64d\n",ans);
return 0;
}
E.
题意:n个棍子,一次取,如果当前棍子的长度和重量都大于等于上一个棍子时,ans + 1,求ans的最小值
解析:按照重量排序,重量一样按照棍子长度从小到大排序。每次用过的标记一下
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>
#include <algorithm>
#include <list>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
using namespace std;
struct S
{
int l,w;
bool operator < (const S x) const
{
if(l == x.l)
return w < x.w;
return l < x.l;
}
} a[5005];
bool vis[5005];
int main()
{
freopen("in.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
memset(vis,false,sizeof(vis));
int n;
scanf("%d",&n);
for(int i = 0; i < n; i++)
{
scanf("%d%d",&a[i].l,&a[i].w);
}
sort(a,a + n);
int ans = 0;
while(1)
{
int bl = -1,bw = -1;
bool flag = false;
for(int i =0; i < n; i ++)
{
if(vis[i] == false && a[i].l >= bl && a[i].w >= bw)
{
bl = a[i].l,bw = a[i].w;
vis[i] = true;
}
}
ans ++;
for(int i = 0; i < n; i ++)
{
if(vis[i] == false){
flag = true;
break;
}
}
if(flag == false)
{
break;
}
}
printf("%d\n",ans);
}
return 0;
}
F.
题意: n个人玩儿牌,每个人m张牌。给你你的牌,问你最少能赢几次。没有一样的牌
解析:在其余的玩儿牌人中,直接挑出剩下的牌中最大的 m张。如果你肯定能赢,那么就只能用你最大的牌赢人家最小的牌。如果你可能输,则只能是差一点儿输
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>
#include <algorithm>
#include <list>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
using namespace std;
int a[1005],b[1005];
bool vis[1005];
int main()
{
//freopen("in.txt","r",stdin);
int t = 0;
while(1)
{
memset(vis,false,sizeof(vis));
int n,m;
scanf("%d%d",&n,&m);
if(n == 0 && m == 0)
break;
t ++;
printf("Case %d: ",t);
for(int i = 0; i < m; i ++)
{
scanf("%d",&a[i]);
vis[a[i]] = true;
}
int num = 0;
for(int i = n * m; i > 0; i --)
{
if(vis[i] == false)
{
b[num++] = i;
if(num == m)
{
break;
}
}
}
sort(a,a + m);
sort(b,b + m);
int ans = 0,numb = m;
for(int i = 0; i < m; i ++)
{
if(a[m - 1 - i] > b[numb - 1])
{
//和最小的比,b整体左移
for(int j = 0; j < numb - 1; j ++)
{
b[j] = b[j + 1];
}
ans ++;
}
else
{
int p = numb - 1;
for(int t = p; t >= 0; t--)
{
if(b[t] < a[m - 1 - i])
{
p = t + 1;
for(int j = p; j < numb - 1; j ++)
{
b[j] = b[j + 1];
}
break;
}
}
}
numb --;
}
printf("%d\n",ans);
}
return 0;
}
G.
题意:给你n个作业,每个作业有一个deadline和一个价值。问你最少的没完成作业的价值和
思路:先按照价值排序,并将写作业的时间安排在deadline那一天,如果被占了,在往前递推
代码:
//先按权重排序,然后将其排在能排的最后一个位置
#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>
#include <algorithm>
#include <list>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
using namespace std;
struct TT
{
int t,v;
bool operator < (const TT x)const
{
return v > x.v;
}
} a[1005];
bool vis[1005];
int main()
{
//freopen("in.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
memset(vis,false,sizeof(vis));
int n;
scanf("%d",&n);
for(int i = 0; i < n; i ++)
{
scanf("%d",&a[i].t);
}
for(int i = 0; i< n; i ++)
{
scanf("%d",&a[i].v);
}
sort(a, a + n);
int ans = 0;
for(int i = 0; i < n; i ++)
{
int m = a[i].t;
bool flag = false;
for(int j = m; j >= 1; j --)
{
if(vis[j] == false)
{
vis[j] = true;
flag = true;
break;
}
}
if(flag == false)
{
ans += a[i].v;
}
}
printf("%d\n",ans);
}
return 0;
}
H.
题意:n个节目,都有一个开始时间和结束时间问最多能看多少个节目(如果开始时间等于结束时间,表示是可以连着看的)
解析:紫书区间贪心
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>
#include <algorithm>
#include <list>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
using namespace std;
struct TT
{
int l,r;
bool operator < (const TT x)const//先判断右端点.左端点越大越好
{
if(r == x.r)
return l > x.l;
return r <x.r;
}
}a[105];
int main()
{
//freopen("in.txt","r",stdin);
int n;
while(1)
{
scanf("%d",&n);
if(n == 0)
break;
for(int i = 0; i < n; i ++)
{
scanf("%d%d",&a[i].l,&a[i].r);
}
sort(a,a + n);
int bg = -1,ans = 0;
for(int i = 0; i < n; i ++)
{
if(a[i].l >= bg)
{
ans ++;
bg = a[i].r;
}
}
printf("%d\n",ans);
}
return 0;
}
I.
题意:超市n样产品,每样产品都有一个价值和一个卖出时间,只有早于等于这个时间卖出才是有价值的。问最多的价值和是多少
解析:同作业那题G
代码:
//先按权重排序,然后将其排在能排的最后一个位置
//和G题基本相同,记得该数组的大小
#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>
#include <algorithm>
#include <list>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
using namespace std;
struct TT
{
int t,v;
bool operator < (const TT x)const
{
return v > x.v;
}
} a[10005];
bool vis[10005];
int main()
{
//freopen("in.txt","r",stdin);
int T,n;
while(scanf("%d",&n) != EOF)
{
memset(vis,false,sizeof(vis));
for(int i = 0; i < n; i ++)
{
scanf("%d%d",&a[i].v,&a[i].t);
}
sort(a, a + n);
int ans = 0;
for(int i = 0; i < n; i ++)
{
int m = a[i].t;
for(int j = m; j >= 1; j --)
{
if(vis[j] == false)
{
vis[j] = true;
ans += a[i].v;
break;
}
}
}
printf("%d\n",ans);
}
return 0;
}
J.
题意:在y大于0的xy坐标轴上有几个点,有一个规定的半径r问,至少要在x坐标轴上有多少个点,才能将这些点全都圈进(包括边缘)圆中。如果不可行输出-1
解析:既然是找点画圆,不妨干脆以给出点为中心画圆,如果这个圆不与x轴相交,则一定不行,直接输出-1.如果相交则求出交点的范围。如果两个圆在x轴的范围是有重叠的,那么着两个点,就可以被同一个圆圈住。那么就等价于n个区间,求为了使得每个区间中都有一个点,点的个数(见紫书)
代码:
//区间选点问题,使得每个区间都包含一个点,最少点的个数
//如果相交就加进去
//确定一个点的位置再判断该点可以在几个区间中
#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>
#include <algorithm>
#include <list>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
using namespace std;
struct P
{
double l,r;
bool operator < (const P x)const
{
if(r == x.r)
return l > x.l;
return r < x.r;
}
} a[1005];
bool vis[1005];
int main()
{
// freopen("in.txt","r",stdin);
int t = 0;
while(1)
{
bool mflag =false;
memset(vis,false,sizeof(vis));
int n,r,x,y,ans = 0;
scanf("%d%d",&n,&r);
if(n == 0 && r == 0)
break;
t ++;
printf("Case %d: ",t);
for(int i = 0; i < n; i ++)
{
scanf("%d%d",&x,&y);
a[i].l =1.0 * x - sqrt(r * r * 1.0 - y* y);
a[i].r =1.0 * x + sqrt(r * r * 1.0 - y* y);
if(y > r)
{
mflag = true;
}
}
if(mflag == true)
{
printf("-1\n");
continue;
}
sort(a,a + n);
double now;
while(1)
{
now = 100000000000;
//确定一个点的位置再判断该点可以在几个区间中
for(int i = 0; i < n; i ++)
{
if(a[i].l <= now && vis[i] == false)
{
now = a[i].r;
vis[i] = true;
break;
}
}
for(int i = 0; i < n; i ++)
{
if(a[i].l <= now && vis[i] == false)
{
vis[i] = true;
}
}
ans ++;
bool flag = false;
for(int i = 0; i < n; i ++)
{
if(vis[i] == false)
{
flag = true;
break;
}
}
if(flag == false)
{
break;
}
}
printf("%d\n",ans);
}
return 0;
}
K.
题意:m个坑,你要用长度为n的木板填坑。每个坑表示的是左端点和右端点。问至少需要用几个木板。每个坑不重叠
分析:因为不重叠,按照多端点和右端点排序都行。然后直接模拟放木板。注意一个细节。如果当前位置全部已经被木板所覆盖了的情况
代码:
//未能独立ac
#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>
#include <algorithm>
#include <list>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
using namespace std;
struct P
{
long long l,r;
bool operator < (const P x) const
{
return l < x.l;
}
}a[10005];
int main()
{
//freopen("in.txt","r",stdin);
long long n,l;
scanf("%I64d%I64d",&n,&l);
for(int i = 0; i < n; i ++)
{
scanf("%I64d%I64d",&a[i].l,&a[i].r);
}
sort(a,a + n);
long long left = -1,ans = 0;
for(int i = 0; i < n; i ++)
{
if(a[i].r < left)//此条件为未考虑到的条件。上一块板子可能将该部分的板子全部覆盖完全
{
continue;
}
left = max(left,a[i].l);
long long num = a[i].r - left;
if(num % l != 0)
{
left = a[i].r + (l - num % l);//该点的左边已被覆盖
}
else
left = a[i].r;
ans += (num + l - 1) / l;
}
printf("%I64d\n",ans);
return 0;
}
L.
题意:一个人在点0,各点之间都有一个单向的路,可以从当前点i走到i+1.每个点都有一个鱼池,最开始的5min能钓到鱼的期望数为f[i].没过5min减少d[i],如果减少之后剩下鱼的数目小于等于0,则不会再钓到鱼了。一个人有h小时的时间。问为了钓到最多的鱼,他在每个鱼池里呆的时间是多长(如果每个都一样,则待在第一个鱼池),以及最多钓到鱼数目的期望
解析:贪心 + 枚举
枚举最远能走到多远。这样只需要在总时间中,减去走路用的时间,再贪心,每次钓鱼后,都比较一下那个鱼池里的鱼多(注意该鱼池是能够到达的)。如果鱼数目相同就去前面的鱼池,注意比较的条件
另:注意输出格式,够奇葩
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>
#include <algorithm>
#include <list>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
using namespace std;
struct PP
{
int f,d;
int id;
bool operator < (const PP x)const
{
if(f== x.f)
return id < x.id;
return f > x.f;
}
} a[30],b[30];
int t[30];
int time[30],atime[30];
int main()
{
//freopen("in.txt","r",stdin);
int h,n;
bool mflag = false;
while(1)
{
scanf("%d",&n);
if(n == 0)
break;
scanf("%d",&h);
h = h * 12;
for(int i = 0; i < n; i ++)
{
scanf("%d",&b[i].f);
b[i].id = i;
}
for(int i = 0; i < n; i ++)
{
scanf("%d",&b[i].d);
}
for(int i = 1; i < n; i ++)
{
scanf("%d",&t[i]);
t[i] += t[i - 1];
}
int maxn = -1,hh;
for(int de = 0; de < n; de ++)
{
memset(time,0,sizeof(time));
hh = h - t[de];
int ans = 0;
for(int i = 0; i < n; i ++)
{
a[i].f = b[i].f,a[i].d = b[i].d;
a[i].id = b[i].id;
}
while(hh > 0)
{
sort(a,a + n);
int p = 0;
for(; p <n; p ++)
{
if(a[p].f > 0 && a[p].id <= de)
{
break;
}
}
if(p == n)
{
p = 0;
a[p].f = 0;
time[0] ++;
hh --;
continue;
}
ans += a[p].f;
a[p].f -= a[p].d;
hh = hh - 1;
time[a[p].id] ++;
}
if(ans > maxn)
{
maxn = ans;
for(int i = 0; i < n; i ++)
{
atime[i] = time[i];
}
}
// cout<<ans<<endl;
}
if(mflag )
printf("\n");
printf("%d",atime[0] * 5);
for(int i = 1; i < n; i ++)
{
printf(", %d",atime[i] * 5);
}
printf(" \n");
printf("Number of fish expected: %d \n",maxn);
mflag = true;
}
return 0;
}
M.(不够理解)
题意:给你一棵树,每个点有个价值,你依次遍历整棵树,只有遍历了该节点的父节点,才能遍历该节点。结果等于当前时第几步乘以该节点价值的和。求最小的价值
解析:如果没有树,肯定是每次先遍历最大的价值点,也就是说一旦该点的父节点染色完毕,那么下一个要染色的点一定是该点。我们可以将该点合并到其父节点上去。而合并也是有花费的,花费就是当前点的总价值,乘以父节点已有节点的个数。父节点的总个数增加该节点的个数,总节点也增加了该节点的个数。下次比较时比较的是每个节点的平均值,总价值/总个数。(已经把如果接着走因为步数的增加而带来的价值减去了)并且如果该点是其他点的父节点,那么其他点的父节点变为该点的父节点。注意要保证该节点不是根节点。因为要保证该节点是有父节点的
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>
#include <algorithm>
#include <list>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
using namespace std;
struct node
{
int s,c;
int pre;
double w;
}a[1005];
int n,r;
int getMin()
{
int p;
double maxx = -1000000000;
for(int i = 0; i < n; i ++)
{
if(i == r)
continue;
if(a[i].w > maxx)
{
maxx = a[i].w;
p = i;
}
}
return p;
}
int main()
{
//freopen("in.txt","r",stdin);
while(1)
{
scanf("%d%d",&n,&r);
if(n == 0 && r == 0)
break;
r --;
int u,v,s;
int ans = 0;
for(int i = 0; i < n; i ++)
{
scanf("%d",&s);
a[i].s = s,a[i].c = 1;
a[i].w = 1.0 * a[i].s /a[i].c;
}
for(int i = 0; i < n - 1; i ++)
{
scanf("%d%d",&u,&v);
u --,v --;
a[v].pre = u;
}
for(int i = 0; i < n - 1; i ++)
{
int p = getMin();
int fa = a[p].pre;
ans += a[fa].c * a[p].s;
a[fa].s += a[p].s;
a[fa].c += a[p].c;
a[fa].w = 1.0 * a[fa].s / a[fa].c;
a[p].w = 0;
for(int j = 0; j < n; j ++)
{
if(a[j].pre == p)
{
a[j].pre = fa;
}
}
//cout<<ans<<endl;
}
ans += a[r ].s;
printf("%d\n",ans);
}
return 0;
}