poj Crane 线段树变种

2024-01-08 06:32
文章标签 poj 线段 变种 crane

本文主要是介绍poj Crane 线段树变种,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

今天刚刚看了线段树,以为挺简单,不就就是一个区间的最小值,靠父亲节点来判断~。

谁知,看了后面的一道运用线段树的问题,顿时傻眼了再见,代码看了好多遍,根本就是 就是 就是啥也不懂呗。。。。还能是神马。然后就是老规矩,看网上题解。。。然而这次居然不灵了,还是没怎么懂,然后,然后,然后就是去洗衣服去了呗,还能干神马。神奇的是,在洗衣服过程中,我居然有点想通了。。。。       有点激动地来跟大家分享一下。

 

首先明确各种题解中的坐标不是单个棍子首尾2端点各自的坐标,而是在特定的区间内所有棍子合起来的(可以看作一个向量)的坐标。而这个特定区间其实就是 线段树分成的各个区间呗。。。。(一直平分,直到最后是剩下叶节点),而我们学习的线段树的根节点代表整个区域的最小值,是根据其2个儿子节点的数值,比较得来的,如果改变某一叶节点的值,会相应的改变包含其的所有节点的值。同理:在此题中,根节点的坐标就是所有棍子合起来的坐标呗,它的值是根据其2个儿子节点的数值合起来的呗。。。。。然后往下推一直到叶节点。。。而转动某一根棍子,相当于把线段树中的叶节点的值给改变了呗,咱们就要相应地改变包含这根棍子的所有节点(区域)的值。思路就是这样。。。。。

 

下面代码是书上的。。。。。

#include<stdio.h>
#include<math.h>
#define M_PI acos(-1.0)
#define SIZE 100100
int N,C;
int L[20010],S[20010],A[20010];
double vx[SIZE<<2],vy[SIZE<<2],ang[SIZE<<2],prv[10010];
void init(int k,int l,int r)
{int chl,chr;ang[k]=vx[k]=0.0;if(r-l==1)vy[k]=L[l];else{chl=k*2+1;chr=k*2+2;init(chl,l,(l+r)/2);init(chr,(l+r)/2,r);vy[k]=vy[chl]+vy[chr];}
}
void change(int s,double a,int v,int l,int r)
{int chl,chr,m;double ss,c;if(s<=l)return ;elseif(s<r){chl=v*2+1;chr=v*2+2;m=(l+r)/2;change(s,a,chl,l,m);change(s,a,chr,m,r);if(s<=m){ang[v]+=a;}ss=sin(ang[v]);c=cos(ang[v]);vx[v]=vx[chl]+(c*vx[chr]-ss*vy[chr]);vy[v]=vy[chl]+(ss*vx[chr]+c*vy[chr]);}
}
int main(void)
{int s,i;double a;while(scanf("%d%d",&N,&C)!=EOF){for(i=0;i<N;i++)scanf("%d",&L[i]);for(i=0;i<C;i++)scanf("%d%d",&S[i],&A[i]);init(0,0,N);for(i=1;i<N;i++)prv[i]=M_PI;for(i=0;i<C;i++){s=S[i];a=A[i]*2*M_PI/360.0;change(s,a-prv[s],0,0,N);prv[s]=a;printf("%.2f %.2f\n",vx[0],vy[0]);}}}
 
 
 
 
 
#include<stdio.h>
#include<math.h>
#define lc p<<1,s,mid
#define rc p<<1|1,mid+1,e
#define mid ((s+e)>>1)
#define N 10005
#define pi acos(-1.0)
#define eps 1e-8
double x[N>>2],y[N>>2],rot[N>>2];
double rad[N];void rotate(double &x,double &y,double r)
{double xx=x;x=xx*cos(r)-y*sin(r);y=xx*sin(r)+y*cos(r);
}
void pushup(int p)
{x[p]=x[p<<1]+x[p<<1|1];y[p]=y[p<<1]+y[p<<1|1];
}
void pushdown(int p,int s,int e)
{int lp,rp;if(fabs(rot[p])>eps)return ;lp=p<<1;rp=p<<1|1;rot[lp]+=rot[p];rot[rp]+=rot[p];rotate(x[lp],y[lp],rot[p]);rotate(x[rp],y[rp],rot[p]);rot[p]=0;
}
void build(int p,int s,int e)
{rot[p]=0;if(s==e){scanf("%lf",&y[p]);x[p]=0;rad[s]=pi;return ;}build(lc);build(rc);pushup(p);
}
void update(int p,int s,int e,int l,int r,double v)
{if(l<=s&&e<=r){rot[p]+=v;rotate(x[p],y[p],v);return ;}pushdown(p,s,e);if(l<=mid)update(lc,l,r,v);if(r>mid)update(rc,l,r,v);pushup(p);
}
int main(void)
{int n,m,p,first=1;double r;while(~scanf("%d%d",&n,&m)){build(1,1,n);while(m--){scanf("%d%lf",&p,&r);r=r/180.0*pi;update(1,1,n,p+1,n,r-rad[p]);rad[p]=r;printf("%.2lf %.2lf\n",x[1],y[1]);}}}



这篇关于poj Crane 线段树变种的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/582560

相关文章

poj3468(线段树成段更新模板题)

题意:包括两个操作:1、将[a.b]上的数字加上v;2、查询区间[a,b]上的和 下面的介绍是下解题思路: 首先介绍  lazy-tag思想:用一个变量记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。 比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in

hdu1689(线段树成段更新)

两种操作:1、set区间[a,b]上数字为v;2、查询[ 1 , n ]上的sum 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>#include<map>#include<stdio.h>#include<stdl

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

poj 1511 Invitation Cards(spfa最短路)

题意是给你点与点之间的距离,求来回到点1的最短路中的边权和。 因为边很大,不能用原来的dijkstra什么的,所以用spfa来做。并且注意要用long long int 来存储。 稍微改了一下学长的模板。 stack stl 实现代码: #include<stdio.h>#include<stack>using namespace std;const int M

poj 3259 uva 558 Wormholes(bellman最短路负权回路判断)

poj 3259: 题意:John的农场里n块地,m条路连接两块地,w个虫洞,虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。 任务是求你会不会在从某块地出发后又回来,看到了离开之前的自己。 判断树中是否存在负权回路就ok了。 bellman代码: #include<stdio.h>const int MaxN = 501;//农场数const int

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

poj 1287 Networking(prim or kruscal最小生成树)

题意给你点与点间距离,求最小生成树。 注意点是,两点之间可能有不同的路,输入的时候选择最小的,和之前有道最短路WA的题目类似。 prim代码: #include<stdio.h>const int MaxN = 51;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int P;int prim(){bool vis[MaxN];

poj 2349 Arctic Network uva 10369(prim or kruscal最小生成树)

题目很麻烦,因为不熟悉最小生成树的算法调试了好久。 感觉网上的题目解释都没说得很清楚,不适合新手。自己写一个。 题意:给你点的坐标,然后两点间可以有两种方式来通信:第一种是卫星通信,第二种是无线电通信。 卫星通信:任何两个有卫星频道的点间都可以直接建立连接,与点间的距离无关; 无线电通信:两个点之间的距离不能超过D,无线电收发器的功率越大,D越大,越昂贵。 计算无线电收发器D