您的位置:首页 > 其它

HDU 5475 平衡树/线段树

2015-10-21 00:09 441 查看
题目意思百度上到处都是啊~

题目大意:

有一个特殊的计算器,初始值 X = 1。现在有两种操作:

1. 乘以 Y

2. 除以一个之前乘过的数。

每次操作之后,输出对 M 取余的值。

方法1(错误):

根据题目意思,用同余计算。

但是这里的要取余的数字是不是素数!所以这个方法不对

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <math.h>
#include <vector>
#include <map>
#include <stack>
#include <algorithm>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::sort;
using std::min;
using std::max;
using std::vector;
#define LL long long

LL n, mod;
const int MAXN = 100000 + 1000;
LL a[MAXN];

LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
LL r=exgcd(b,a%b,x,y);
LL t=x;
x=y;
y=t-a/b*y;
return r;
}

/*
bool modular_linear_equation(LL a,LL b,LL n)
{
LL x,y,x0,i;
LL d=exgcd(a,n,x,y);
if(b%d)
return false;
x0=x*(b/d)%n;   //特解
cout<<"!"<<d<<endl;
for(i=1;i<d;i++)
printf("%d\n",(x0+i*(n/d))%n);
return true;
}
*/

LL  modular_linear_equation(LL a,LL b,LL n)
{
LL x,y,x0,i;
LL d=exgcd(a,n,x,y);
if(b%d)
{
while (1)
{
cout<<"!!"<<endl;
}
} //无解,但是这个题不可能的
x0=x*(b/d)%n;   //特解
// x0 = (x0 + n) % n;
return x0;
}

int main()
{
//cout<<modular_linear_equation(1, 2, 100);
//return 0;
//freopen("a.txt","w",stdout);
int ttt;
scanf("%d", &ttt);
for (int j = 1; j <= ttt; ++ j)
{
printf("Case #%d:\n", j);
scanf("%I64d%I64d", &n, &mod);
LL now = 1LL;
int tot = 0; //存在多少个整数倍
for (int i = 1; i <= n ; ++ i) //要修改
{
LL flag;
scanf("%I64d%I64d", &flag, &a[i]);
if (now == 0 && tot == 0)	now = mod;
if (flag == 1LL)
{
if (a[i] % mod == 0)	++tot;
else now = (now * a[i]) % mod;
if (now == 0)	tot ++;
}
if (flag == 2LL)
{
LL A = a[a[i]];
if (A % mod == 0)
{
--tot;
goto xxx;//如果去掉了一个整数倍的,不用计算
}
if (mod % A == 0) --tot;
LL B = now;
LL willnow = modular_linear_equation(A, B, mod);
now = willnow % mod;
}
xxx:;
now = now % mod;
if (tot) printf("0\n");
else printf("%I64d\n", now);
}
}
return 0;
}


方法2:线段树

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using std::cin;
using std::cout;
using std::endl;
using std::min;
using std::max;

#define LL long long
int n;
LL mod;

struct node
{
int L, R;
LL key;
int ls,rs;
void clear()
{
key = 1;
}
node():key(1),L(-1),R(-1), ls(-1), rs(-1){}
}t[100000 * 2 + 200];
int tail=0;

void make_tree(int now, int ll, int RR)
{
t[now].L = ll;
t[now].R = RR;
t[now].key = 1; //全部都为1
if (ll == RR) return;
int mid = (ll + RR) / 2;
t[now].ls = ++ tail;
make_tree(tail, ll, mid);
t[now].rs = ++ tail;
make_tree(tail, mid + 1, RR);
}

LL change_tree(int now, int k, LL p) //在k位置改为p
{
if (t[now].L == k && t[now].R == k)
{
t[now].key = p;
return p;
}
int mid = (t[now].L + t[now].R) / 2;
if (k <= mid) change_tree(t[now].ls, k, p);
if (mid < k) change_tree(t[now].rs, k, p);
LL a = t[t[now].ls].key;
LL b = t[t[now].rs].key;
t[now].key = (a * b) % mod;
return (a * b) % mod;
}

int main()
{
int tt, tmp;
scanf("%d", &tt);
make_tree(0, 1, 100001);
for (int ttt = 1; ttt <= tt; ++ ttt)
{
for (int i = 0; i != tail + 10; ++ i) t[i].clear();//tree init
printf("Case #%d:\n", ttt);
scanf("%d%I64d", &n, &mod);
for (int i = 1; i <= n; ++ i)
{
int flag;
LL num;
scanf("%d%I64d", &flag, &num);
if (flag == 1) cout << change_tree(0, i, num);
else cout << change_tree(0, num, 1) ;
cout << endl;
}
}
return 0;
}


方法3:平衡树。

类似平衡树维护总和的方法,来维护一颗平衡树的积。

比赛时候一个int没改为LL所以错了,这让我十分十分的忧伤!不然就区域赛出线了,哎。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <math.h>
#include <vector>
#include <map>
#include <stack>
#include <algorithm>
#include <vector>
#pragma comment(linker, "/STACK:102400000,102400000")
using std::cin;
using std::cout;
using std::endl;
using std::sort;
using std::min;
using std::max;
using std::vector;
#define LL long long

LL n, mod;
const int MAXN = 200010;

struct Size_Balabced_Tree{
int left[MAXN],right[MAXN],s[MAXN],root,tt;
LL w[MAXN], key[MAXN];
void clear(){
memset(left,0,sizeof(left));
memset(right,0,sizeof(right));
memset(s,0,sizeof(s));
for (int i = 0; i != MAXN; ++ i)    w[i] = key[i] = 1;
root=tt=0;
}
void gr(int &t){
int k=left[t];
left[t]=right[k];
right[k]=t;
s[k]=s[t];
w[k] = w[t]; //
s[t]=s[left[t]]+s[right[t]]+1;
w[t] = ((w[left[t]] * w[right[t]])%mod * key[t]) % mod;//
t=k;
}
void gl(int &t){
int k=right[t];
right[t]=left[k];
left[k]=t;
s[k]=s[t];
s[t]=s[left[t]]+s[right[t]]+1;
w[k] = w[t];//
w[t] =(( w[left[t]] * w[right[t]]) % mod * key[t]) % mod;
t=k;
}
void _insert(int &t,LL v){
if (!t){
t=++tt;
key[t]=v;
w[t] = v; //
s[t]=1;
return ;
}
++s[t];
w[t] = (w[t] * v) % mod;
if (v<key[t]){
_insert(left[t],v);
if (s[left[left[t]]]>s[right[t]]) gr(t);

}
else{
_insert(right[t],v);
if (s[right[right[t]]]>s[left[t]]) gl(t);
}
w[t] = ((w[left[t]] * w[right[t]] % mod ) * key[t] ) % mod;
}
LL _dele(int &t,LL v){
LL ans;
--s[t];
if (v==key[t] || v<key[t] && !left[t] || v>key[t] && !right[t])
{
ans=key[t];
if (!left[t] || !right[t]) t=left[t]+right[t];
else key[t]=_dele(left[t],v+1);
}
else
if (v<key[t]) ans=_dele(left[t],v);
else ans=_dele(right[t],v);
w[t] = ((w[left[t]] * w[right[t]] % mod)* key[t]) % mod;//
return ans;
}
bool _find(int &t,LL v){
if (!t) return false;
if (key[t]==v) return true;
if (v<key[t]) return _find(left[t],v);
else return _find(right[t],v);
}
LL _rank(int &t,LL v){   //查v的排名
if (t==0) return 1;
if (v<=key[t]) return _rank(left[t],v);
else return s[left[t]]+1+ _rank(right[t],v);
}
LL _selectmintomax(int &t,LL k){  //查第k名 (从小到大)
if (k==s[left[t]]+1) return key[t];
if (k<=s[left[t]]) return _selectmintomax(left[t],k);
else return _selectmintomax(right[t],k-1-s[left[t]]);
}
int _selectmaxtomin(int &t,int k){ //查第k名 从大到小排名
if (k==s[right[t]]+1) return key[t];
if (k<=s[right[t]]) return _selectmaxtomin(right[t],k);
else return _selectmaxtomin(left[t],k-1-s[right[t]]);
}
int _pred(int &t,int v){  //找比v小的最大的 找不到就返回自己
int ans;
if (t==0) return v;
if (v<=key[t]) ans=_pred(left[t],v);
else{
ans=_pred(right[t],v);
if (ans==v) ans=key[t];
}
return ans;
}
int _succ(int &t,int v){ //找比v大的最小的数字 找不到返回自己
int ans;
if (t==0) return v;
if (v>=key[t]) ans=_succ(right[t],v);
else {
ans=_succ(left[t],v);
if (ans==v) ans=key[t];
}
return ans;
}
void insert(int k){   //插入K
_insert(root,k);
}
bool find(int k){     //查找K,返回ture false
return _find(root,k);
}
int dele(int k){     //删除K,如果有就删掉,没有就删掉遍历到的最后一个数字,并且返回这个数字(你可以重新插入)
return _dele(root,k);
}
int rank(int k){    //查找K在树种的排名,从小到大排名
return _rank(root,k);
}
int selectmintomax(int k){  //插找第K小元素
return _selectmintomax(root,k);
}
int selectmaxtomin(int k){  //查找第K大元素
return _selectmaxtomin(root,k);
}
int pred(int k){  //找比K小的最大的数字
return _pred(root,k);
}
int succ(int k){  //找比K大的最小的数字
return _succ(root,k);
}
}SBT;
LL a[MAXN];

void pg()
{
cout<<"root="<<SBT.root<<endl;
for (int i = 0; i <= 15; ++ i)
{
cout <<" i="<<i<<" left="<< SBT.left[i] <<" right=" <<SBT.right[i] <<" s=" << SBT.s[i] << " key="<< SBT.key[i]<<" w="<<SBT.w[i]<<endl;
}
}

int main()
{
//	int size = 256 << 20; // 256MB
//char *p = (char*)malloc(size) + size;
//   __asm__("movl %0, %%esp\n" :: "r"(p));
//freopen("a.txt","w",stdout);
int ttt;
scanf("%d", &ttt);
for (int j = 1; j <= ttt; ++ j)
{
printf("Case #%d:\n", j);
SBT.clear();
SBT.insert(1);
scanf("%I64d%I64d", &n, &mod);
for (int i = 1; i <= n ; ++ i) //要修改
{
LL flag;
scanf("%I64d%I64d", &flag, &a[i]);
if (flag == 1)    SBT.insert(a[i]);
if (flag == 2)    SBT.dele(a[a[i]]);
printf("%I64d\n", (SBT.w[SBT.root]) % mod);
}
//pg();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  平衡树 线段树