8.22

POJ 1984 Navigation Nightmare(路径压缩并查集)

并查集,给n个点和m条边,每条边有方向和长度,再给q个询问,第i个询问查询两个点之间在Ti时刻时的曼哈顿距离(能连通则输出曼哈顿距离,否则输出-1

http://images.cnitblog.com/blog/591194/201401/03134632-ccc7c8865b924d70825412b5a035e58e.jpg

这题还要注意数据可能不是按照时间顺序输入的,要做按时间顺序由小到大排序,然后再按原来的顺序输出。还是路径压缩的一套不过这次有两个r[]数组,rx[i]表示i节点到父亲节点的x距离,ry[i]同理,输入m条边时,

for (i=1;i<=m;i++)

    {

        scanf("%d%d%d %c",&x[i],&y[i],&d,&c);

        switch(c)

        {

            case 'W':dx[i]=-d;dy[i]=0;break;//西

            case 'S':dx[i]=0;dy[i]=-d;break;

            case 'E':dx[i]=d;dy[i]=0;break;

            case 'N':dx[i]=0;dy[i]=d;break;

        }

}

for (i=1;i<=k;i++)

    {

        for (;j<=a[i].idx;j++)

        {

            fx=find(x[j]);fy=find(y[j]);

            fa[fy]=fx;

            rx[fy]=rx[x[j]]-rx[y[j]]-dx[j];//到根节点的距离,fxfy左边为负,右边为正

            ry[fy]=ry[x[j]]-ry[y[j]]-dy[j];//fxfy上方

为正,下为负

        }

        if (find(a[i].x)!=find(a[i].y))

            ans[a[i].n]=-1;

        else

            ans[a[i].n]=abs(rx[a[i].x]-rx[a[i].y])+abs(ry[a[i].x]-ry[a[i].y]);

    }

POJ 2631 Roads in the North(树的直径)

求树上最长的两个点之间的距离。这里有一个结论,在图中,要找到距离最远的两点,先随便从一个点入手bfs,找到距离这个点最远的点,在从这个点bfs找到距离这点最远的点,这两点之间的距离就是这颗树的直径。即首先从树上任意一个点a出发, (BFS)找出到这个点距离最远的点b. 然后在从b点出发(BFS)找到距离b点最远的点c. 那么bc间的距离就是树的直径.所以直接进行bfs搜索就行了

poj 1985 Cow Marathon 【树的直径】

和上一道题目一样,裸题。

树状数组只能计算A[1]开始的和,A[0]这个元素是不能用的,复杂度O(logn)。执行n次add操作,总时间复杂度O(nlogn)。注意,刚开始c数组要初始全0,然后每读入一个数A[i]就执行一步add(i, A[i])来进行真正的初始化。

且树状数组处理的数组A[n]是从小标1开始的,也即A[0]是一个没有用的元素。

C数组中的每一个元素都是A数组中的一段连续和。

HDU 1166 敌兵布阵(简单树状数组)

树状数组裸题

UVA1428 Ping pong(树状数组)

先别想与树状数组有什么联系?先想拿到这个题目怎么做?很容易想到枚举谁可以当裁判,但裁判的条件是,假设c是裁判,a,b是对手,则a<=c<=b,即裁判能力值介于比赛者之间,且比赛选手是在裁判住所两侧各挑一个,不能都在同一侧,他当裁判时有几种比赛组织方式。对于第i个裁判,他能组织多少种比赛?

假设a1~a[i-1]有L个能力值比a[i]小的,那么比a[i]大的i-1-L个

A[i+1]~a[n]有R个能力值比a[i]小的,那么比a[i]大的有n-i-R个

··················i················

L个小于等于a[i]                      R个小于等于a[i]

i-1-L个比a[i]大                    n-i-R个比a[i]大

显然,第i个裁判可以组织的比赛场数

L*(n-i-R)+(i-1-L)*R。

问题就转化成了,对于每个裁判怎么求其,L,R,这个地方就可以用树状数组了。

对每个i,求左边比他小的数,正着跑一边,这个数出现了,就在他的位置加1,对于每个数,先求一下比他小的有几个,再把这个数add进去。

对每个I,求右边比他小的数,倒着跑一边,这个输出现,就在他的位置+1,对于每个数,先求一下比他小的有几个,再把这个数add进去。

3 4 5 1 1 2为例

求左边

C数组

1位置     2位置        3位置      4位置     5位置

  0          0            0           0          0

Sum(3)=0,显然左边比3小的没有

Add(3,1)

   0          0            1           0          0

Sum(4)=1,显然左边比4小的有一个

Add(4,1)

   0           0            1           1

Sum(5)=2,显然左边比5小的有两个

Add(5,1)

   0           0             1          1          1]

Sum(1)=0,显然1左边小于等于它的没有

Add(1,1)

   1           0             1           1         1

Sum(1)=1,显然1左边小于等于它的有一个

Add(1,1)

   2           0             1           1         1

Sum(2)=2,显然2左边小于等于它的有2个

求右边类似

C数组

1位置     2位置        3位置      4位置     5位置

  0          0            0           0          0

Sum(2)=0;

Add(2,1)

   0         1             0          0         0

Sum(1)=0

Add(1,1)

   1          1            0           0         0

Sum(1)=1

Add(1,1)

   2           1           0           0         0

····

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值